Есть ли способ заставить PHP ждать, пока MySQL не завершит транзакцию? - PullRequest
5 голосов
/ 19 июня 2009

Я признаю, что я не на 100% во внутренней работе PDO и MySQL, поэтому приведу пример, чтобы прояснить мой вопрос.

Я делаю довольно грубую браузерную стратегическую игру, потому что считаю, что это увлекательный способ изучения PHP и баз данных. Я тестировал сценарий битвы, когда наткнулся на довольно неожиданную ошибку. Я использую Cron Jobs для вызова сценария каждую минуту, который выглядит примерно так:

$ sql = "ВЫБЕРИТЕ Army_id ОТ активной армии ГДЕ прибытие = 0;";

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

        battleEngine($row["army_id"]);

    }

Когда базовые вычисления сделаны (атакующая армия против обороняющейся армии), шесть таблиц в базе данных обновляются. Проблема, с которой я сталкиваюсь, заключается в том, что когда я совершаю несколько атак на одну и ту же цель в течение одной минуты, то время от времени одна из этих атак извлекает устаревшую информацию из базы данных (в одном крайнем случае атака № 10 выбирает ту же таблицу, что и атака № 5) ,

Полагаю, это происходит потому, что скрипт работает быстрее, чем база данных? Есть ли способ заставить PHP ждать, пока вся необходимая информация не появится, прежде чем повторять функцию со следующей строкой $?

РЕДАКТИРОВАТЬ: Эмиль, вероятно, правильно. Однако я не могу убедиться, так как для моего PDO кажется невозможным оставаться открытым достаточно долго, чтобы я мог передать несколько операторов между beginTransaction () и commit (). Тем не менее, грязное чтение кажется странным, так как я использую InnoDB с «REPEATABLE READ». Некоторые Google предлагают, что REPEATABLE READ сделает грязное чтение невозможным. Задумавшись над тем, как покончить с собой, я решил вместо этого взломать. На данный момент я поместил UPDATE для специального значения сверху моего скрипта, а другое в конце большого пакета (около шести операторов UPDATE) внизу. Перед запуском функции я установил цикл while (), который проверяет, установлено ли для этого специального значения значение 0. Если это не так, он спит в течение 0,01 секунды и пытается снова. Глядя на вывод, цикл while повторяется в среднем два раза, предполагая, что он действительно может работать? Это еще не удалось, но это может быть потому, что это не час пик. Я попробую снова через регулярные интервалы завтра. Я знаю, что никто не заботится обо всем этом, но я чувствовал, что должен сделать это обновление на всякий случай. = P

Ответы [ 3 ]

2 голосов
/ 19 июня 2009

То, что вы видите, называется «грязным чтением». Используйте InnoDB и установите уровень изоляции в сериализуемое значение. Затем оберните все запросы в блоки транзакций:

$dbh->beginTransaction();
// run queries
$dbh->commit();
1 голос
/ 19 июня 2009

Если бы PHP просто подождал, вы бы получили большое количество заданий cron, накапливающихся в.

То, что вы действительно хотите, - это использовать что-то вроде anachron, чтобы убедиться, что в любой момент времени выполняется только один экземпляр скрипта. Также вы можете сделать что-то вроде следующего:

<?php

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

  // do your stuff

  unlink('/tmp/myscriptlock');
0 голосов
/ 26 июня 2009

Моей первоначальной мыслью была простая блокировка записи mysql, но я недостаточно хорошо понимаю проблему. В любом случае это может помочь: http://www.perplexedlabs.com/2008/02/06/mutex-with-php-and-mysql/

...