Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php PDO';MySQL的lastInsertId是否存在竞争条件?_Php_Mysql_Pdo - Fatal编程技术网

Php PDO';MySQL的lastInsertId是否存在竞争条件?

Php PDO';MySQL的lastInsertId是否存在竞争条件?,php,mysql,pdo,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-

我正在编写一个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。为了解决这个问题,我添加了一个随机睡眠(在上面注释掉),它纠正了这个问题。我正在使用事务,我相信它会纠正这个问题。我是不是漏掉了什么明显的东西

对于那些好奇的人,以下是我的桌子设置:

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不会将一个会话的最后一个插入id返回给另一个会话

说:

生成的ID在服务器中按每个连接进行维护。这意味着函数返回给给定客户机的值是为影响该客户机自动增量列的最新语句生成的第一个自动增量值。此值不受其他客户端的影响,即使它们生成自己的自动增量值。此行为确保每个客户端都可以检索自己的ID,而不必关心其他客户端的活动,也不需要锁或事务


您的评论如下:

这是MySQL从一开始的行为。如果最后一个insert ID易受竞争条件的影响,即如果其他会话中的insert会污染您的会话,那么返回最后一个insert ID将是非常无用的

一种可能性是您使用的是持久连接,因为旧版本的PHP有一个bug,即可以给新的PHP请求一个连接,并从以前的PHP请求中授予对会话作用域状态的访问权。换句话说,锁、事务、临时表、用户变量和最后一个插入id等内容可以保存到后续的PHP请求中。这些问题应该在PHP5.3中用mysqlnd驱动程序解决;持久连接应“重置”为初始状态

另一种可能的解释是,它确实正常工作,而你的观察是错误的。因此,我建议仔细、系统地测试它


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

问题是Chrome内置控制台的网络选项卡没有显示正确的信息。通过console.log()显示ID按预期工作,使用Firefox的FireBug按预期显示网络活动。我的工作假设是“网络”选项卡将显示实际的网络活动,但并不总是如此。

你说“两者”的值相同是什么意思?都是什么?每次调用PHP文件时,它都会实例化类的一个新实例。在本例中,该文件被调用两次,因此创建了该类的两个实例。执行上述代码后,这两个实例的
id
属性值相同。看起来,您正在尝试放置比microtime更精确的内容,对吗?不,
microtime()
只是显示查询执行得非常接近。问题是,如果两个查询同时执行,则在查询1之后插入查询2,但在查询1检索lastInsertId之前插入。因此,DB向查询1提供属于查询2的ID号(因为查询2是最后一次插入)。查询2还获取属于查询2的ID,因为它是最后一个INSERT。表是否由非事务性存储引擎(如MyISAM)支持,连续的INSERT是否共享同一个数据库连接?但这又如何解释我的问题?这似乎与我所经历的直接矛盾。事实上,我在调查时确实读过这篇文章,因为这不是我的代码的作用方式,所以我在这里发布了。此外,我确实将我的版本列为5.1.69,而不是链接引用的版本(5.6)。然而,在这种情况下,所讨论的段落是相同的。