【发布时间】: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 行锁也将被释放。所以我不明白。
谢谢。
【问题讨论】: