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

时间:2009-06-18 22:59:12

标签: php sql mysql pdo transactions

我承认我不是百分之百地讨论PDO和MySQL的内部工作原因,所以我举一个例子让我的问题更清楚。

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

  

$ sql =“SELECT army_id FROM activearmy WHERE arrival = 0;”;

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

        battleEngine($row["army_id"]);

    }

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

我猜这是因为脚本比数据库快?有没有办法强制PHP等到所有相关信息都到位后才重复下一个$行的函数?

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

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

如果PHP只是完全等待,那么你将获得大量的cron工作。

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

<?php

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

  // do your stuff

  unlink('/tmp/myscriptlock');

答案 2 :(得分:0)

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