обработка отката транзакций базы данных в PHP - PullRequest
2 голосов
/ 03 марта 2010
try
{
  $con->beginTransaction();

  $this->doSave($con);

  $con->commit();
}
catch (Exception $e)
{
  $con->rollBack();

  throw $e;
}

Приведенный выше код является вполне стандартным подходом к транзакциям,

но мой вопрос: что делать, если $con->rollBack() также не работает?

Это может вызвать блокировку БД, верно? Если да, то каков идеальный путь?

Ответы [ 3 ]

4 голосов
/ 03 марта 2010

При использовании транзакций основная идея состоит в том, что на самом деле ничто не будет постоянно записываться в базу данных до тех пор, пока не будет вызван commit.

Пара ситуаций:

  • Если вы:
    • начать транзакцию
    • выполнить несколько запросов
    • Откат
    • Затем запросы откатываются; что означает, что их результат не записывается в базу данных.
  • Если вы:
    • начать транзакцию
    • выполнить несколько запросов
    • отключить (что происходит, если ваш PHP-скрипт заканчивается - например, из-за фатальной ошибки или die)
    • Тогда запросы не фиксируются - это означает, что они не записываются в базу данных; это означает, что это так же, как если бы был rollback.


Для простоты: начиная с begin transaction, в базу данных ничего не записывается, пока вы не отправите commit. Если нет фиксации ... Ничего не пишется постоянно, и когда ваш PHP-скрипт отключается от БД, БД «отменяет» то, что этот PHP-скрипт не зафиксировал.

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

1 голос
/ 03 марта 2010

MySQL обрабатывает ситуацию с ошибкой, откатывая саму транзакцию.

Откат может быть медленной операцией, которая может происходить неявно без явного запроса пользователя (например, при возникновении ошибки).

Документация MySQL охватывает ваше "что, если дело"

Если сеанс с отключенной автоматической фиксацией завершается без явной фиксации последней транзакции, MySQL откатывает эту транзакцию.

Далее:

И фиксация, и откат снимают все блокировки InnoDB, которые были установлены во время текущей транзакции.

Редактировать: Я настроил тест для предложенной вами ситуации. Использование таблицы innoDB с MySQL 5.

$db = new DB();
$db->beginTransaction();
$db->exec("INSERT INTO `table` (`val`) VALUES('commit?')");
sleep(30);
$db->commit();

Это работает, как я описал ниже в комментариях. Если разрешение завершено, транзакция фиксируется в таблице через 30 секунд.

Если я уничтожу сценарий, прежде чем разрешить его завершить, транзакции откатываются и таблица остается в чистом состоянии - как и ожидалось.

0 голосов
/ 03 марта 2010

Используйте ядро ​​транзакционной базы данных, такое как InnoDB . Это гарантирует целостность данных в случае сбоя запроса во время записи. MySQL по умолчанию использует движок MyISAM, который работает быстрее и является не транзакционным. Все, что вам нужно сделать, это изменить механизм хранения при создании базы данных.

...