给一个真实存在的id范围加FOR UPDATE,再往三个不同位置插入数据,用performance_schema.data_locks确认间隙锁到底锁住了哪几段。
accounts表的id取值是10,20,30,...,80,中间天然留着一个个间隙。
session ASTART TRANSACTION; SELECT * FROM accounts WHERE id BETWEEN 10 AND 30 FOR UPDATE; SELECT SLEEP(6); COMMIT;
lock_type lock_mode lock_data RECORD X 20 ← next-key锁:真实覆盖(10,20)这个间隙 + 记录20本身 RECORD X 30 ← next-key锁:真实覆盖(20,30)这个间隙 + 记录30本身 RECORD X,REC_NOT_GAP 10 ← 纯记录锁:真实没有锁10前面的间隙
这条BETWEEN 10 AND 30真实只产生了3条锁记录,而不是给整个索引都加锁:id=10上真实标了REC_NOT_GAP,说明它前面的间隙没被锁;id=20和id=30上真实是普通的X锁(不带REC_NOT_GAP,也不带纯GAP标记),这种"记录锁+它前面的间隙锁"合在一起的锁,就是Next-Key Lock,下一篇会专门拆开看。
插入 id=15(在(10,20)间隙内部): ERROR 1205 Lock wait timeout ← 真实被挡住 插入 id=5(在10前面,锁没覆盖到): 成功,真实立即完成 插入 id=35(在30后面,锁没覆盖到): 成功,真实立即完成
每一步都是本文上面用真实并发会话跑出来的原始结果。
performance_schema.data_locks:真实查看锁的具体范围和类型