5

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

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

$sql = "从现役军队中选择军队 ID,到达地点 = 0;";

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

        battleEngine($row["army_id"]);

    }

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

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

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

4

3 回答 3

2

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

$dbh->beginTransaction();
// run queries
$dbh->commit();
于 2009-06-18T23:07:22.187 回答
1

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

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

<?php

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

  // do your stuff

  unlink('/tmp/myscriptlock');
于 2009-06-18T23:04:01.260 回答
0

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

于 2009-06-26T05:03:51.070 回答