TRX1 select * from table where refId = 4 for update
TRX2 插入表(refId)值(2);块
trx2将被阻止,我知道trx1会保持间隙锁定,[1,4],[4,7];
我的问题是为什么要保持差距? "插入val 2"不是冲突"选择refId = 4进行更新",为什么innodb会保持间隙锁定,为什么不使用记录锁?
这个问题困扰了我好久,请科技上帝拯救我。
答案 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中进行间隙锁定?