有没有办法强制 PHP 等待 MySQL 完成事务?

Posted

技术标签:

【中文标题】有没有办法强制 PHP 等待 MySQL 完成事务?【英文标题】:Is there a way to force PHP into waiting until MySQL is finished with a transaction? 【发布时间】:2010-11-04 04:14:40 【问题描述】:

我承认我不是 100% 了解 PDO 和 mysql 的内部工作原理,所以我举个例子让我的问题更清楚。

我正在制作一个相当粗糙的基于浏览器的策略游戏,因为我认为这是一种学习 php 和数据库的有趣方式。当我遇到一个相当意外的错误时,我正在对战斗脚本进行错误测试。我使用 Cron Jobs 每分钟调用一个脚本,看起来像这样:

$sql = "SELECT Army_id FROM activearmy WHEREarrival=0;";

foreach($dbh->query($sql) as $row)
    

        battleEngine($row["army_id"]);

    

当基本计算完成后(攻击军与防御军),数据库中的六个表被更新。我面临的问题是,当我在同一分钟内对同一目标进行多次攻击时,其中一次攻击时不时地获取过时的数据库信息(在一种极端情况下,攻击 #10 获取与攻击 #5 相同的表) .

我猜这是因为脚本比数据库快?有没有办法强制 PHP 等到所有相关信息都准备好后再用下一个 $row 重复该函数?

编辑:Emil 可能是正确的。我不能确定,因为我的 PDO 似乎不可能保持打开足够长的时间让我在 beginTransaction() 和 commit() 之间传递几个语句。但是,脏读似乎很奇怪,因为我将 InnoDB 与“REPEATABLE READ”一起使用。一些谷歌搜索建议 REPEATABLE READ 将使脏读变得不可能。在考虑了一段时间如何杀死自己之后,我选择了破解。现在,我将一个特殊值的 UPDATE 放在我的脚本顶部,另一个放在底部的大批量(大约六个 UPDATE 语句)的末尾。在运行该函数之前,我已经建立了一个 while() 循环来检查该特殊值是否设置为 0。如果不是,它会休眠 0.01 秒并重试。查看输出,while 循环平均重复两次,这表明它实际上可能正在工作?它还没有失败,但可能是因为它不是高峰时间。明天我会定期再试一次。我知道没有人关心这一切,但我觉得我应该做这个更新以防万一。 =P

【问题讨论】:

【参考方案1】:

您所看到的称为“脏读”。使用 InnoDB 并将 isolation level 设置为可序列化。然后将所有查询包装在事务块中:

$dbh->beginTransaction();
// run queries
$dbh->commit();

【讨论】:

【参考方案2】:

如果 PHP 完全等待,您将获得大量的 cron 作业。

真正想要的是使用 anachron 之类的东西,以确保在任何给定时刻只有一个脚本实例运行。您也可以执行以下操作:

<?php

  if (file_exists('/tmp/myscriptlock')) exit();
  touch('/tmp/myscriptlock');

  // do your stuff

  unlink('/tmp/myscriptlock');

【讨论】:

最好使用 MySQL 锁,这样如果作业和连接终止,那么锁会自动释放。 dev.mysql.com/doc/refman/5.0/en/…【参考方案3】:

我最初的想法是简单的mysql写锁,但我对这个问题理解得不够好。无论如何,这可能会有所帮助:http://www.perplexedlabs.com/2008/02/06/mutex-with-php-and-mysql/

【讨论】:

以上是关于有没有办法强制 PHP 等待 MySQL 完成事务?的主要内容,如果未能解决你的问题,请参考以下文章

如何强制 Crashlytics 上传报告并等待

MySQL事务没有提交导致 锁等待Lock wait timeout exceeded异常

有没有办法在不等待命令完成的情况下使用 shell_exec ?

mysql中innodb引擎的行锁是通过加在啥上完成

多数据库事务:mysql、SQL server 和 PHP

强制一种方法等待另一种方法完成