有没有办法强制 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 完成事务?的主要内容,如果未能解决你的问题,请参考以下文章
MySQL事务没有提交导致 锁等待Lock wait timeout exceeded异常