通过PHP进行MySQL死锁检测

时间:2009-10-12 12:58:07

标签: php mysql transactions

在PHP中处理MySQL死锁的最佳做法是什么?我应该在try {} catch {}块中包装所有数据库调用,并从数据库中查找DeadLock错误代码吗?然后我再次重新发出整个交易(我假设那个故意回滚的那个)?

2 个答案:

答案 0 :(得分:5)

死锁返回错误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

答案 1 :(得分:3)

我想引用MySQL How to Cope with Deadlocks

中的这些热情话语
  

如果由于死锁而失败,请务必重新发布交易。死锁并不危险。再试一次。

这可以通过以下模式实现:

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;
        }
    }
}