2009-10-12 65 views
1

在PHP中处理MySQL死锁的最佳做法是什么?我是否应该将所有数据库调用都封装在try {} catch {}块中,并从数据库中查找DeadLock错误代码?然后我是否再次重新发布整个交易(我认为失败的回滚)?通过PHP检测MySQL死锁

回答

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

+0

@RomanNewaza:因为交易双方锁定两个表,尽管在不同的顺序。 – Quassnoi 2013-01-29 07:27:52

+0

是的,我明白了。谢谢! – 2013-01-29 07:53:09

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