You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL自增主键为何持有间隙锁并引发死锁?技术问询

自增主键间隙锁引发死锁的问题解析

核心疑问解答:为何主键索引上加间隙锁而非记录锁

  1. INSERT IGNORE的锁行为特性
    因为表存在唯一键uk_lock_table_01(user_id,order_code),INSERT IGNORE执行时会先对每条待插入记录做唯一键冲突检查:

    • 若检查到记录已存在,直接忽略插入;
    • 若未命中记录,InnoDB在RR隔离级别下,会对唯一索引的对应间隙加锁(防止幻读和并发插入重复键),同时该锁会关联到主键索引的对应间隙(二级索引叶子节点存储主键值,锁会同步到主键索引)。
  2. 自增主键的间隙锁逻辑
    自增主键id按顺序分配,批量插入时InnoDB会预先分配一批自增ID,为了保证自增ID的连续性和插入顺序,会在主键索引的目标插入间隙(待插入记录的主键值所在区间)加间隙锁,而非针对已存在的记录加记录锁——毕竟待插入的主键记录还不存在,自然不会有记录锁。

死锁触发的具体流程

结合死锁日志来看:

  1. 会话2先执行批量INSERT IGNORE,对部分待插入的(user_id,order_code)做冲突检查,未命中记录后,在主键索引的某个间隙加了X型间隙锁;
  2. 会话1执行自己的批量INSERT IGNORE,其中某条记录的插入间隙被会话2持有,于是等待该间隙的插入意向锁;
  3. 会话2继续处理后续批量插入记录,发现需要申请的间隙锁被会话1持有(会话1在之前的冲突检查中也加了其他间隙锁),同样进入等待;
  4. 双方互相持有对方需要的锁,形成循环等待,触发死锁。

优化建议

  • 拆分批量插入为单条插入,缩小单次操作的锁范围,降低冲突概率;
  • 若业务允许,改用INSERT ... ON DUPLICATE KEY UPDATE替代INSERT IGNORE,其锁行为更可控;
  • 确保uk_lock_table_01索引统计信息准确,避免InnoDB因索引失效执行全表扫描,导致锁范围扩大;
  • 调整innodb_autoinc_lock_mode参数(默认值为1),批量插入时减少锁的持有时间,但需注意自增ID可能出现不连续的情况。

内容的提问来源于stack exchange,提问作者linlowa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 05:43:14