1

我有时会收到 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;");      
    }

我也是:

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

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

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

同样,我的更新和删除仅更新和删除分配给它们的 process_id 的行......并且我在其中执行“SELECT rows ... FOR UPDATE”的事务是 process_id = null 的地方。从理论上讲,它们永远不应该重叠。

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

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

任何帮助深表感谢

4

3 回答 3

6

死锁发生在两个或多个进程请求锁定时,被锁定的资源重叠,但发生顺序不同,因此每个进程都在等待被另一个进程锁定的资源,而另一个进程正在等待锁定原始进程已打开。

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

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

于 2011-11-07T16:54:28.997 回答
4

You might want to try LOCK TABLES before starting the transaction, thereby assuring you have explicit control over the tables. The lock will wait until all activity on the particular tables has completed.

于 2011-11-07T19:40:03.050 回答
2

我想网上的每个人都已经很好地解释了僵局。Mysql 提供了非常好的日志来检查所有最后发生的死锁以及当时哪些查询被卡住了。检查这个mysql 文档页面并搜索LATEST DETECTED DEADLOCK 其出色的日志,帮助发现许多微妙的死锁。

于 2013-06-22T15:58:35.513 回答