MySQL高并发修改主键易死锁,本质是删旧行+插新行引发的X锁与间隙锁环形等待,叠加索引变更、锁序不一致及全表扫描导致。

高并发修改主键(尤其是自增主键)本身不会直接死锁,真正触发死锁的是修改过程中隐含的索引变更、唯一性校验和行锁顺序冲突。 主键不是“被改”的对象,而是整行数据重定位的过程——InnoDB 会先删除旧记录(加 X 锁),再插入新记录(加 X 锁 + 间隙锁),这个“删-插”原子动作在并发下极易形成环形等待。
UPDATE id WHERE 条件不走索引,触发全表扫描加锁
当执行类似 UPDATE t SET id = id + 1000 WHERE status = 'pending',而 status 字段没有索引时:
- InnoDB 必须全表扫描,对**每条匹配行加 X 锁**,对**每个扫描到的间隙加 Gap Lock**(RR 隔离级别下)
- 不同事务扫描顺序可能不同(如一个按聚簇索引正序,另一个因缓冲池状态反序),导致加锁顺序不一致
- 若两个事务都扫到同一组行但加锁顺序相反,就构成经典死锁四元组:T1 锁 A→等 B,T2 锁 B→等 A
- 即使只改主键值,只要 WHERE 条件没走索引,就等于在高并发下“手动实现表锁”
主键变更引发二级索引重建,锁范围意外扩大
主键是聚簇索引,所有二级索引的叶节点都存着主键值。当 id 被 UPDATE,InnoDB 不仅要更新聚簇索引,还要同步更新所有二级索引项:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 每条二级索引记录的修改,都会触发对应聚簇索引记录的查找 → 可能再次加 X 锁或 Gap Lock
- 如果二级索引字段本身也参与 WHERE 或 ORDER BY,还会额外引入更多锁竞争点
- 例如:
UPDATE t SET id = id * 2 WHERE create_time > '2026-01-01',若create_time有索引,但该索引是 (create_time, id) 联合索引,那么更新 id 会导致该联合索引中大量叶子节点分裂/移动,锁住相邻间隙 - 这种“间接锁扩散”很难从 SQL 表面察觉,需结合
SHOW ENGINE INNODB STATUS\G中的LOCK WAIT和TRANSACTIONS段分析
记录迁移过程中的“删除旧行 + 插入新行”非原子性暴露
InnoDB 修改主键本质是物理迁移:先标记旧记录为删除(加 X 锁),再在新位置插入(加 X 锁 + Gap Lock)。这个过程在并发下可被拆解观察:
- 事务 T1 执行
UPDATE t SET id = 101 WHERE id = 1:先对 id=1 加 X 锁,再尝试在 id=101 的位置插入 → 若该位置已被 T2 的间隙锁封锁,则 T1 等待 - 事务 T2 同时执行
UPDATE t SET id = 1 WHERE id = 101:先对 id=101 加 X 锁,再尝试在 id=1 插入 → 若 id=1 正被 T1 持有,则 T2 等待 - 此时形成闭环:T1 等 T2 释放 id=101 的间隙,T2 等 T1 释放 id=1 的行锁
- 注意:即使 id 是唯一键,InnoDB 仍会在插入前检查间隙是否允许插入,这就是 Gap Lock 的作用点
批量主键调整时 ID 列表未排序,放大锁序混乱风险
业务中常见“迁移老数据”场景,如把旧库 id 批量 +1000000:
- 若传入的 ID 列表是乱序的(如 [5, 1, 9, 3]),各事务按各自顺序遍历更新,必然导致加锁顺序不一致
- 正确做法是强制排序:
UPDATE t SET id = id + 1000000 WHERE id IN (1,3,5,9) ORDER BY id—— 虽然ORDER BY对 UPDATE 无效,但应用层必须先SELECT ... ORDER BY id获取有序 ID,再逐条或分批更新 - 更稳妥的是用临时表 + JOIN 方式批量更新,确保物理扫描顺序与业务逻辑顺序一致
- 避免 ORM 自动生成的 IN 子句(如 MyBatis 的
<foreach></foreach>)不保证顺序,需显式加ORDER BY或改用绑定参数数组
真正危险的从来不是“改主键”这个动作,而是改的过程中对索引结构的扰动、对锁边界的误判,以及开发时对 InnoDB 底层迁移逻辑的无感。线上做主键迁移前,务必用 EXPLAIN FORMAT=tree 看执行计划,用 SELECT * FROM performance_schema.data_locks 抓锁详情,否则你以为的“单条 update”,可能是并发下的锁风暴入口。

















