Php MySQL在相同数据集但不同线程上的荒谬行为

Php MySQL在相同数据集但不同线程上的荒谬行为,php,mysql,mysqli,Php,Mysql,Mysqli,我从两个不同的PHP实例连接到MySQL db。第一个线程添加新行,通过队列将新行的“id”传递给第二个线程。有时,第二个线程无法找到新行数据,即使理论上它应该在第一个线程完成其工作后到达db 简化的伪代码看起来像 线程1 $db = get_mysql_connection(); $db->beginTransaction(); $rowid = $db->query("insert data.."); $db->commit(); //For Debugging purp

我从两个不同的PHP实例连接到MySQL db。第一个线程添加新行,通过队列将新行的“id”传递给第二个线程。有时,第二个线程无法找到新行数据,即使理论上它应该在第一个线程完成其工作后到达db

简化的伪代码看起来像

线程1

$db = get_mysql_connection();
$db->beginTransaction();
$rowid = $db->query("insert data..");
$db->commit();

//For Debugging purposes only
$db->check_if_row_exists($rowid); //Always returns true

send_to_queue($rowid);
线程2

$rowid = fetch_from_queue();
$db = get_mysql_connection();
$db->check_if_row_exists($rowid); //Sometimes returns false;
usleep(1000000);
$db->check_if_row_exists($rowid); //Always returns true.
我无法理解,为什么线程1显示数据有一个有效的条目,而线程2(当然在线程1之后的某个时间进行查询)无法找到数据。我正在使用事务提交数据,这是在做一些奇怪的事情吗

我用Gearman作为队列。线程1通过Apache运行,而线程2只是作为独立进程运行

编辑1: 当线程2与线程1同时运行时,就会发生这种情况。显然,线程1达到了某种竞争条件,但我不明白为什么

编辑2: 正如N.B.所指出的,Innodb延迟将数据写入磁盘,因此第二个线程看不到数据


我应该如何处理这种情况?Sleep/Usleep几乎总是次优的解决方案,因为在高负载条件下,磁盘i/o时间可能会增加。是否有某种方法“通知”第二个线程Innodb已完成其磁盘i/o?

从我的评论粘贴,无需更改任何内容:


这里没有比赛条件。线程1可以看到它的事务 和数据。线程2无法,因为它们尚未到达磁盘。否 InnoDB尚未发出fsync呼叫。所以很自然,你会永远 请参阅线程1中的数据,但如果它在运行时不在磁盘上 调用-在线程2中看不到它。线程1和线程2不支持 共享相同的mysql连接线程,两者使用不同的线程。所以 简而言之,如果不在磁盘上,则没有可用的数据。它不在磁盘上 因为InnoDB将延迟写入,直到驱动器准备好写入。 这就是为什么你在美国睡后看到它


从我的评论中粘贴,无需更改任何内容:


这里没有比赛条件。线程1可以看到它的事务 和数据。线程2无法,因为它们尚未到达磁盘。否 InnoDB尚未发出fsync呼叫。所以很自然,你会永远 请参阅线程1中的数据,但如果它在运行时不在磁盘上 调用-在线程2中看不到它。线程1和线程2不支持 共享相同的mysql连接线程,两者使用不同的线程。所以 简而言之,如果不在磁盘上,则没有可用的数据。它不在磁盘上 因为InnoDB将延迟写入,直到驱动器准备好写入。 这就是为什么你在美国睡后看到它


您确定rowid总是成功地传输到另一个线程吗?是的。注意第二个检查行是否存在调用。它总是返回true。请将该行添加到线程1示例,其中第二个线程被传递id。这里没有争用条件。线程1可以查看其事务和数据。线程2不能,因为他们还没有到达磁盘,InnoDB还没有发出fsync调用。因此,很自然,您总是会看到来自线程1的数据,但是如果调用时数据不在磁盘上,那么您就不会在线程2中看到它。线程1和线程2不共享同一个mysql连接线程,它们都使用不同的线程。因此,简而言之,如果不在磁盘上,就没有可用的数据。它不在磁盘上,因为InnoDB将延迟写入,直到驱动器准备好写入。这就是为什么你在usleep后看到它。检查你的InnoDB设置,例如:InnoDB\u flush\u log\u at\u trx\u commit。根据您的设置,不能保证数据会立即刷新到磁盘。更改这些设置很可能会影响性能,因此请小心。您确定rowid总是成功地传输到另一个线程吗?是的。注意第二个检查行是否存在调用。它总是返回true。请将该行添加到线程1示例,其中第二个线程被传递id。这里没有争用条件。线程1可以查看其事务和数据。线程2不能,因为他们还没有到达磁盘,InnoDB还没有发出fsync调用。因此,很自然,您总是会看到来自线程1的数据,但是如果调用时数据不在磁盘上,那么您就不会在线程2中看到它。线程1和线程2不共享同一个mysql连接线程,它们都使用不同的线程。因此,简而言之,如果不在磁盘上,就没有可用的数据。它不在磁盘上,因为InnoDB将延迟写入,直到驱动器准备好写入。这就是为什么你在usleep后看到它。检查你的InnoDB设置,例如:InnoDB\u flush\u log\u at\u trx\u commit。根据您的设置,不能保证数据会立即刷新到磁盘。更改这些设置很可能会影响性能,因此请小心。