php - MySQL 的 PDO 的 lastInsertId 竞争条件?

标签 php mysql pdo

我正在编写一个 PHP 类文件,它使用 PDO 将数据推送到 MySQL 数据库。本质上,该文件很快被多次访问(每次都创建该类的一个新实例),并且 lastInsertId() 方法跟不上。例如:

//sleep(rand(100,1000)/100);
$sql = "INSERT INTO `testing` (`name`, `timestamp`) VALUES (?, ?)";
$this->dbh->beginTransaction();
$sth = $this->dbh->prepare($sql);
$sth->bindValue(1, $_POST["name"]);
$sth->bindValue(2, microtime());
$sth->execute();
$this->id = $this->dbh->lastInsertId();
$this->dbh->commit();

如果页面被快速调用两次,当返回 $this->id 时,两个实例的值都是 2,尽管 DB 看起来像这样:

+----+--------+-----------------------+
| id | name   | timestamp             |
+----+--------+-----------------------+
|  1 | Mark   | 0.98705900 1385770566 |
|  2 | George | 0.99367300 1385770566 |
+----+--------+-----------------------+

问题是执行的第一个查询的 id 值应该为 1,而执行的第二个查询的 id 值应该为 2。为了解决这个问题,我添加了一个随机 sleep (上面已注释掉)并解决了这个问题。我正在使用交易,我相信这会解决这个问题。我在这里遗漏了什么明显的东西吗?

对于那些好奇的人,这是我的 table 设置:

CREATE TABLE `testing` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(255) NOT NULL,
    `timestamp` varchar(255) NOT NULL,
     PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

PHP 5.3.3
MySQL 5.1.69

最佳答案

MySQL 不会将一个 session 的最后插入 ID 返回给另一个 session 。

http://dev.mysql.com/doc/refman/5.6/en/information-functions.html#function_last-insert-id说:

The ID that was generated is maintained in the server on a per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client. This value cannot be affected by other clients, even if they generate AUTO_INCREMENT values of their own. This behavior ensures that each client can retrieve its own ID without concern for the activity of other clients, and without the need for locks or transactions.


回复你的评论:

从一开始这就是 MySQL 的行为。如果最后一个插入 ID 容易受到竞争条件的影响,那么返回最后一个插入 ID 将毫无用处,也就是说,如果其他 session 中的插入可能会污染您的 session 。

一种可能性是您正在使用持久连接,因为旧版本的 PHP 有一个错误,即可以将连接提供给新的 PHP 请求,并授予对先前 PHP 请求的 session 范围状态的访问权限。换句话说,锁和事务、临时表和用户变量以及最后插入的 id 之类的东西可以在后续的 PHP 请求中存活下来。这些问题应该在带有 mysqlnd 驱动程序的 PHP 5.3 中得到解决;持久连接应该“重置”到初始状态。

另一种可能的解释是它确实在正常运行,而您的观察有误。因此,我建议仔细而有条不紊地对其进行测试。

更新根据your answer ,此问题与 MySQL 或 PDO 或 lastInsertId 无关。听起来您根本没有看到 PHP 代码输出中的差异,您在 Chrome 开发工具中看到了意外的网络性能统计数据。

关于php - MySQL 的 PDO 的 lastInsertId 竞争条件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20295097/

相关文章:

php - 通过php将数据插入mysql多对多关系

java - 我们如何在 Hibernate 中按日期对结果进行排序?

php - JSON 数据发布但表未填充

php - PDO 绑定(bind)参数不起作用

php - PHP中@符号的用途是什么?

MySql:连接有重复项的列

java - 从服务器文件系统获取图像到android应用程序?

php - 如何将 PDO 数据库中的项目检索到数组中以检索字符串

php - 在 localhost 的 php 中创建一个个性化的 404 错误页面

php - 根据相同的键连接数组值