我从两个不同的PHP实例连接到MySQL数据库。第一个线程添加一个新行,通过队列将新行的“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的第二个线程?
答案 0 :(得分:0)
从我的评论中发现,没有必要改变任何东西:
这里没有竞争条件。线程1可以看到它的交易 和数据。线程2不能,因为它们还没有到达磁盘(没有 InnoDB已经进行了fsync调用。很自然,你永远都是 查看来自线程1的数据,但是如果它在当时不在磁盘上 调用 - 你不会在线程2中看到它。线程1和2不会 共享SAME mysql连接线程,两者都使用不同的。所以 缩短它 - 如果不是在磁盘上,没有数据可用。它不在磁盘上 因为InnoDB会延迟写入,直到驱动器准备好写入。 这就是为什么你在睡觉后看到它。