【问题标题】:MySQL Deadlock Detection via PHP通过 PHP 检测 MySQL 死锁
【发布时间】:2009-10-12 12:58:06
【问题描述】:

在 PHP 中处理 MySQL 死锁的最佳实践是什么?我是否应该将所有数据库调用包装在 try{}catch{} 块中并从数据库中查找死锁错误代码?然后我是否再次重新发出整个事务(我假设回滚失败的那个)?

【问题讨论】:

    标签: php mysql transactions


    【解决方案1】:

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

    【讨论】:

    • @RomanNewaza:因为两个事务都锁定了两个表,尽管顺序不同。
    【解决方案2】:

    我想引用 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;
            }
        }
    }
    

    【讨论】:

    • 不应使用建议的模式。请参阅this answer 以获得更好的。
    猜你喜欢
    • 2010-12-28
    • 2013-02-20
    • 2010-10-13
    • 1970-01-01
    • 2012-04-06
    • 2019-04-26
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    相关资源
    最近更新 更多