【问题标题】:Why commit does not cause deadlock为什么提交不会导致死锁
【发布时间】:2016-08-26 01:11:27
【问题描述】:

我已经阅读了有关 InnoDB 锁的 mysql 参考手册。我明白了 : (从: http://dev.mysql.com/doc/refman/5.5/en/innodb-locks-set.html)


INSERT 在插入的行上设置排他锁。此锁是索引记录锁,而不是 next-key 锁(即没有间隙锁),并且不会阻止其他会话插入到插入行之前的间隙中。

在插入行之前,设置了一种称为插入意图间隙锁的间隙锁。这个锁表示插入的意图,即如果插入到同一索引间隙中的多个事务没有插入到间隙内的同一位置,则它们不需要相互等待。假设有值为 4 和 7 的索引记录。尝试插入值 5 和 6 的单独事务在获得插入行的排他锁之前,每个使用插入意图锁锁定 4 和 7 之间的间隙,但不相互阻塞,因为行不冲突。

如果发生重复键错误,则会在重复索引记录上设置共享锁。如果另一个会话已经拥有排他锁,那么如果有多个会话尝试插入同一行,则使用共享锁可能会导致死锁。如果另一个会话删除了该行,就会发生这种情况。假设 InnoDB 表 t1 具有以下结构:

CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB; 现在假设三个会话依次执行以下操作:

第 1 节:

START TRANSACTION;
INSERT INTO t1 VALUES(1);

第 2 节:

START TRANSACTION;
INSERT INTO t1 VALUES(1);

第三节:

START TRANSACTION;
INSERT INTO t1 VALUES(1);

第 1 节:

ROLLBACK;

会话 1 的第一个操作获取行的排他锁。会话 2 和 3 的操作都导致重复键错误,并且它们都请求该行的共享锁。当会话 1 回滚时,它会释放其在行上的排他锁,并授予会话 2 和 3 的排队共享锁请求。此时,会话 2 和会话 3 死锁:由于对方持有共享锁,两者都无法获取该行的排他锁。


我做了一个实验,我发现这是事实。

我的问题是:

(1)我发现,如果我提交会话 1,并没有发生死锁。为什么?当我提交会话 1 时,X 行锁也将被释放。所以我不明白。

谢谢。

【问题讨论】:

    标签: mysql database innodb


    【解决方案1】:

    我怀疑这是一个不值得提高效率的极端情况。请注意,您必须获得 3 个会话来尝试抓取同一行——这种情况很少见。你做了一个回滚——也很少见。所以发生的死锁是矫枉过正的,但不值得修复。出于这个原因,必须准备好处理各处的死锁。

    仅供参考,如果这是 Galera 集群的 3 个节点,COMMIT 将出现代码必须处理的错误。如果您将此事务(带有回滚或提交)多次应用于多个节点,我怀疑会发生更多奇怪的组合。

    现在你的问题......大概没有发生死锁,因为其中一个线程获得了排他锁,而另一个线程被“等待”而不是“死锁”击中。

    【讨论】:

    • 大概没有发生死锁,因为其中一个线程获得了排他锁,而另一个线程被“等待”而不是“死锁”击中。---你的意思是 session2 和会话 3 获得了排他锁?他们在收到重复密钥错误后没有请求共享锁吗?
    猜你喜欢
    • 1970-01-01
    • 2015-03-09
    • 2019-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-20
    • 1970-01-01
    • 2012-08-27
    相关资源
    最近更新 更多