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

发布于 2024-07-24 06:12:38 字数 1046 浏览 4 评论 0原文

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

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

$sql =“从activearmy中选择army_id,其中到达=0;”;

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

        battleEngine($row["army_id"]);

    }

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

我猜发生这种情况是因为脚本比数据库更快? 有没有办法强制 PHP 等待所有相关信息都到位后再对下一个 $row 重复该函数?

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

I'll admit I'm not 100 % on the inner workings of PDO and MySQL, so I'll give an example to make my question clearer.

I'm making a rather crude browser based strategy game, because I think it's a fun way to learn PHP and databases. I was bug-testing the battle script when I came across a rather unexpected bug. I use Cron Jobs to call a script each minute, looking something like this:

$sql = "SELECT army_id FROM activearmy WHERE arrival=0;";

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

        battleEngine($row["army_id"]);

    }

When the basic calculations are done (attacking army vs. defending army), six tables in the database is updated. The problem I face is that when I make several attacks at the same target within the same minute, every now and then one of those attacks fetch obsolete database information (in one extreme case, attack #10 fetched the same table as attack #5).

I'm guessing this happens because the script is faster than the database? Is there a way to force PHP to wait until all relevant information is in place before repeating the function with the next $row?

EDIT: Emil is probably correct. I can't make sure though as it seems impossible for my PDO to stay open long enough for me to pass several statements between beginTransaction() and commit(). However, a dirty read seems odd since I'm using InnoDB with "REPEATABLE READ". Some Googling suggest that REPEATABLE READ will make dirty reads impossible. After contemplating how to kill myself for a while, I opted for a hack instead. For now, I put an UPDATE for a special value on top of my script, and another at the end of the big batch (about six UPDATE statements) at the bottom. Before running the function, I've put up a while()-loop which checks if that special value is set to 0. If it's not, it sleeps for 0.01 seconds and try again. Looking at the output, the while loop repeats an average of two times, suggesting it might actually be working? It hasn't failed yet, but it might be because it's not peak hour. I'll try again at regular intervals tomorrow. I know no-one cares about all this, but I felt I should make this update just in case. =P

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

终遇你 2024-07-31 06:12:38

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

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

What you're seeing is called a "dirty read". Use InnoDB and set the isolation level to serializable. Then wrap all the queries in transaction-blocks:

$dbh->beginTransaction();
// run queries
$dbh->commit();
你在看孤独的风景 2024-07-31 06:12:38

如果 PHP 完全等待,您将会收到大量的 cron 作业。

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

<?php

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

  // do your stuff

  unlink('/tmp/myscriptlock');

If PHP would just wait altogether, you would getting a high number of cron jobs stacking up at.

What you really want is to use something like anachron, to make sure only one instance of the script runs at any given moment. Also you could do something like the following:

<?php

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

  // do your stuff

  unlink('/tmp/myscriptlock');
温馨耳语 2024-07-31 06:12:38

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

My initial thought was simple mysql write locks, but I don't understand the problem well enough. In any case this might help: http://www.perplexedlabs.com/2008/02/06/mutex-with-php-and-mysql/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文