这是innodb缺口锁错误吗?

时间:2016-07-29 10:19:34

标签: mysql locking innodb

enter image description here

TRX1 select * from table where refId = 4 for update

TRX2 插入表(refId)值(2);块

trx2将被阻止,我知道trx1会保持间隙锁定,[1,4],[4,7];

我的问题是为什么要保持差距? "插入val 2"不是冲突"选择refId = 4进行更新",为什么innodb会保持间隙锁定,为什么不使用记录锁?

这个问题困扰了我好久,请科技上帝拯救我。

3 个答案:

答案 0 :(得分:1)

有趣的问题。

需要间隙锁定来避免phantom rows。 MySQL默认工作在REPEATABLE-READ隔离级别。如果您在事务中运行多次select ... for update,则应始终返回相同的结果。 假设您没有间隙锁定,并且trx2插入另一行,其中refId = 4(索引不是唯一的)。 然后在trx1中的select后面将返回两行:

MariaDB [test]> select * from t1 where refId=4 for update;
+----+------+
| id | refId|
+----+------+
|  2 |    4 |
|  4 |    4 |
+----+------+
2 rows in set (0.00 sec)

与第一次选择的结果不同。

答案 1 :(得分:0)

  

我知道trx1会保持间隙锁定[1,4),[4,7)

实际上,确切地说,对于非唯一索引,在记录{之前将有(1,4]'next-key'锁(记录+上一个间隔)和(4,7)'gap'锁在记录{ {1}}。您可以使用InnoDB monitor进行检查。

  

“插入val 2”与“选择refId = 4进行更新”没有冲突,为什么innodb将保持间隙锁定,为什么不使用记录锁定?

间隙锁定的目的是防止记录插入到那些间隙中。我敢肯定,当您尝试将记录插入锁定的间隙时,它并不会真正检查或关心记录的7。因此,关键是缝隙已被锁定,无法在此处插入任何内容。

现在,为什么我们需要锁定这些特定的空白?假设我们要用refId插入一条新记录,显然可以将其插入到现有refId = 4记录之后(即refId = 4间隔)或之前(即{{1} }差距)。因此,如果我们仅锁定记录而没有锁定这些间隙,则可以插入此类行。

答案 2 :(得分:0)

MariaDB [test]>从t1中选择*,其中refId = 4进行更新; + ---- + ------ + | id | refId | + ---- + ------ + | 2 | aaaaa | | 4 | bbbbb | + ---- + ------ + 设置2行(0.00秒)

如果refId是不是int的字符串,那么如何在RR模式下在Mysql中进行间隙锁定?