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