MySQL Deadlock Detection через PHP - PullRequest
       16

MySQL Deadlock Detection через PHP

1 голос
/ 12 октября 2009

Какова лучшая практика работы с MySQL Dead-Locks в PHP? Должен ли я обернуть все вызовы базы данных в блок try {} catch {} и найти код ошибки DeadLock в базе данных? Затем я снова перезапускаю всю транзакцию (я полагаю, что откат произошел неудачно)?

Ответы [ 2 ]

5 голосов
/ 12 октября 2009

тупик возвращает ошибку 1213, которую вы должны обработать на стороне клиента

Обратите внимание, что взаимоблокировка и ожидание блокировки - разные вещи. В тупике нет «неудачной» транзакции: они оба виновны. Нет гарантии, какой из них будет отменен.

В таком сценарии возникает тупик:

UPDATE  t_first -- transacion 1 locks t_first
SET     id = 1;

UPDATE  t_second -- transaction 2 locks t_second
SET     id = 2;

UPDATE  t_second -- transaction 1 waits for transaction 2 to release the lock on t_second
SET     id = 2;

UPDATE  t_first -- transaction 2 waits for transaction 1 to release the lock on t_first. DEADLOCK
SET     id = 2;

Вы уверены, что не путаете это с ожиданием блокировки?

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

В приведенном выше примере ожидание блокировки происходит на шаге 3.

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

Вместо этого он просто отменит оператор, который попытался получить блокировку после истечения времени ожидания.

Время ожидания по умолчанию составляет 50 секунд и устанавливается с помощью innodb_lock_wait_timeout.

Сбой оператора (тот, который пытался получить блокировку) вернет ошибку 1205.

3 голосов
/ 03 августа 2015

Я хотел бы процитировать эти теплые слова из MySQL Как справиться с тупиками

Всегда будьте готовы повторно оформить транзакцию, если она не удалась из-за тупика. Тупики не опасны. Просто попробуйте еще раз.

Этого можно добиться с помощью шаблона, подобного этому:

for ($i = 3; true; $i--) {
    $pdo->beginTransaction();
    try {

        // Do the unit of work

        $pdo->commit();
        break;

    } catch (\PDOException $e) {
        $pdo->rollback();
        if ($i <= 0) {
            throw $e;
        }
    }
}
...