MySQL 8.0.26 InnoDB插入操作引发异常死锁问题咨询
MySQL 8.0.26 InnoDB纯INSERT死锁机制解惑
1. 唯一键冲突时,主键索引为何锁定supremum伪记录而非冲突ID?
当INSERT触发唯一键冲突时,InnoDB的锁逻辑和正常插入成功的场景完全不同:
- 首先会在**唯一索引
value**上加S锁,确保其他事务无法修改这条冲突记录,保证唯一性校验的准确性; - 对于主键索引,因为插入会失败,但事务可能后续执行新的插入操作(比如换值重试),InnoDB不会锁定已存在的主键记录,而是锁定主键索引的supremum伪记录(主键索引末尾的虚拟记录)。这个锁的作用是预留主键索引末尾的插入位置,防止其他事务插入新记录干扰当前事务的潜在后续操作,同时避免锁定具体主键记录带来的不必要竞争。
你提到的“INSERT不使用next-key锁”是针对插入成功的场景,冲突插入属于异常分支,官方文档通常不会详细覆盖这种边缘场景。
2. tx1提交后,tx2和tx3为何能同时持有supremum伪记录的X锁?
这是InnoDB针对supremum伪记录的特殊锁兼容规则:
- tx1提交释放锁后,tx2和tx3的INSERT_INTENTION锁会尝试获取supremum的X锁。由于这两个事务的插入目标都是主键索引末尾(自增ID的特性),且它们当前的插入操作都因唯一键冲突处于等待状态,InnoDB允许它们同时持有该X锁——因为此时它们的插入不会产生主键冲突(还没生成最终的自增ID);
- 注意,这种“同时持有”是临时状态,一旦其中一个事务尝试执行新的插入操作,锁兼容就会被打破。
3. 纯INSERT操作为何触发死锁?
死锁的触发路径清晰可查:
- tx1提交后,tx2和tx3都拿到了主键supremum的X锁,同时都在等待唯一索引
value的S锁(用于再次校验'test'是否存在); - 当tx2尝试插入新值(比如
INSERT INTO deadlock_test (value) VALUES ('new_test');),它需要在主键supremum位置插入新记录,但tx3已经持有该位置的X锁,tx2进入等待; - 紧接着tx3也尝试插入新值,它同样需要获取supremum的X锁,但tx2已持有部分锁权限,同时tx2等待tx3释放唯一索引锁,tx3等待tx2释放supremum锁,形成循环等待链,触发InnoDB的死锁检测机制,终止其中一个事务。
关键结论
- 唯一键冲突的INSERT属于异常场景,锁行为不遵循正常插入的规则;
- supremum伪记录的锁兼容是临时的,后续新插入会打破平衡;
- 纯INSERT操作的死锁源于事务间锁资源的循环依赖,无需DELETE或ROLLBACK操作也能触发。
内容的提问来源于stack exchange,提问作者Wodlo
相关产品推荐
相关产品推荐

