避免 MySQL '尝试获取锁时发现死锁;尝试重新启动事务'

dez*_*dez 1 php mysql deadlock database-deadlocks

我有时会收到 mysql 死锁错误说:

'尝试获取锁时发现死锁;尝试重新启动事务'

我有一个队列表,其中多个 php 进程同时运行,从表中选择行。但是,对于每个进程,我希望它每次提取都抓取一组唯一的行,因此我没有选择任何重叠的行。

所以我运行这个查询:(这是我得到死锁错误的查询)

    $this->db->query("START TRANSACTION;");

    $sql = "   SELECT   mailer_queue_id
                FROM    mailer_queues
                WHERE   process_id IS NULL
                LIMIT   250 
                FOR UPDATE;";
    ...


    $sql = "UPDATE  mailer_queues
            SET     process_id = 33044,
                    status = 'COMPLETED'
            WHERE   mailer_queue_id 
                IN  (1,2,3...);";

    ...

    if($this->db->affected_rows() > 0) {
        $this->db->query("COMMIT;");       
    } else{
        $this->db->query("ROLLBACK;");      
    }
Run Code Online (Sandbox Code Playgroud)

我也是:

同时向表中插入行(没有事务/锁)

同时更新表中的行(没有事务/锁)

同时从表中删除行(没有事务/锁)

同样,我的更新和删除只更新和删除它们分配有 process_id 的行......以及我执行“SELECT rows ... FOR UPDATE”事务的地方 process_id = null。理论上,它们永远不应该重叠。

我想知道是否有适当的方法来避免这些死锁?

是否会发生死锁,因为一个事务在选择/更新时锁定表的时间过长,而另一个进程正在尝试执行相同的事务并且只是超时?

任何帮助深表感谢

Mar*_*c B 5

当两个或多个进程以这样一种方式请求锁时会发生死锁,即被锁定的资源重叠,但发生的顺序不同,因此每个进程都在等待被另一个进程锁定的资源,而另一个进程正在等待锁原来的进程已经打开。

在现实世界中,考虑一个建筑工地:你有一把螺丝刀和一个螺丝。两个工人需要驱动一个螺丝。工人 #1 抓住螺丝刀,工人 #2 抓住螺丝。工人 #1 也去抓螺丝,但不能,因为它被工人 #2 握住。工人 #2 需要螺丝刀,但无法拿到,因为工人 #1 拿着它。所以现在他们陷入僵局,无法继续,因为他们已经获得了他们需要的 2 个资源中的 1 个,而且他们都不会客气并“退后一步”。

鉴于您发生了事务外更改,您的一个(或多个)更新/删除可能与您在事务中保留的锁定区域重叠。