MySQL 8.0.26 RR隔离级别下supremum伪记录锁引发死锁疑问
为何REPEATABLE-READ隔离级别下insert ignore会触发supremum伪记录锁并导致死锁?
核心逻辑:RR隔离级别的Next-Key锁机制
在MySQL 8.0.26默认的**REPEATABLE-READ(RR)隔离级别中,InnoDB依赖Next-Key锁(记录锁+间隙锁的组合)**来防止幻读。执行insert ignore时,会经历两个关键步骤:
- 检查唯一约束
uni_key(a,b,c)是否存在冲突记录; - 确认无冲突后,插入新数据,同时需要对自增主键
id对应的索引位置加锁。
supremum伪记录锁的触发原因
自增主键id是有序递增的,新插入记录的id必然是当前表中最大id值+1,也就是插入到主键索引的末尾位置。在RR隔离级别下,InnoDB为了避免其他事务在插入过程中写入更大的id值(引发幻读),会对主键索引的supremum伪记录加间隙锁——这个伪记录是InnoDB为每个索引维护的虚拟末尾节点,代表所有实际记录之后的范围。
当多个会话并发执行insert ignore时,会出现锁持有与等待的交叉:
- 每个会话先持有对应唯一键的检查锁;
- 随后尝试获取主键索引的supremum伪记录锁以完成插入;
这种交叉等待的情况最终会触发死锁。
为何RC隔离级别下无此问题?
在**READ-COMMITTED(RC)**隔离级别中,InnoDB关闭了Next-Key锁的间隙锁部分(仅保留记录锁),同时通过快照读(每次查询读取最新提交的数据版本)来避免幻读。因此执行insert ignore时,只会对实际存在的冲突记录加锁,不会对主键索引的supremum伪记录加间隙锁,自然不会出现争夺伪记录锁导致的死锁。
额外说明
- supremum伪记录锁本质是RR隔离级别下,InnoDB为防护幻读而对索引末尾间隙施加的间隙锁;
insert ignore的冲突检查与插入操作是原子性的,结合RR的锁机制,更容易引发跨会话的锁等待循环,最终导致死锁。
内容的提问来源于stack exchange,提问作者supergaga
相关产品推荐
相关产品推荐

