mysql 5.7死锁频发并非版本缺陷,而是业务逻辑、sql写法与锁机制配合不当所致;典型诱因包括in列表加锁顺序不一致、非唯一索引间隙锁冲突、多表更新顺序混乱、长事务持锁过久,以及rr隔离级别下next-key lock激进导致范围重叠等待。

MySQL 5.7 本身不会“因为版本”直接导致死锁——死锁是事务并发控制的固有现象,InnoDB 引擎在 5.7 中的行为与后续版本(如 8.0)基本一致。真正引发高并发下死锁频发的,是业务逻辑、SQL 写法和锁机制配合不当的结果。
死锁不是 MySQL 5.7 的 bug,而是 InnoDB 锁等待链闭环了
InnoDB 检测到循环等待时,会主动回滚其中一个事务(通常选 undo log 更小的那个),并抛出 Deadlock found when trying to get lock。这不是故障,是正常保护机制。但如果你在 5.7 上高频看到它,说明应用层正在反复制造满足死锁四条件的场景:互斥 + 请求保持 + 不可剥夺 + 循环等待。
为什么高并发下更容易触发?
并发数上去后,事务执行时间差被压缩,加锁顺序冲突的概率指数级上升。常见诱因包括:
- 多个事务对同一组行以不同顺序执行
UPDATE ... WHERE id IN (...)—— MySQL 5.7 不保证IN列表内 ID 的加锁顺序,除非显式排序; -
SELECT ... FOR UPDATE配合非唯一索引或无索引 WHERE 条件,触发间隙锁(Gap Lock),范围重叠时极易形成等待链; - 事务中混合操作多张表,且不同服务/模块更新
orders和inventory的先后顺序不统一; - 长事务持有锁时间过长(比如含 RPC 调用或文件处理),放大了冲突窗口。
MySQL 5.7 特有的陷阱:间隙锁行为更激进
在默认的 REPEATABLE-READ 隔离级别下,5.7 的 InnoDB 对范围查询(如 WHERE price BETWEEN 100 AND 200)会加 Next-Key Lock(记录锁 + 间隙锁)。如果两个事务分别执行:
UPDATE products SET stock = stock - 1 WHERE category_id = 5 AND price > 150;
UPDATE products SET stock = stock - 1 WHERE category_id = 5 AND price <p>即使它们修改的行不重叠,间隙锁覆盖的“空档”可能交叉,导致互相等待。</p><h3>排查必须看 <code>SHOW ENGINE INNODB STATUS\G</code> 的 <code>LATEST DETECTED DEADLOCK</code> </h3><p>这个命令输出里藏着真实线索:</p>
- 注意
WAITING FOR THIS LOCK TO BE GRANTED行,它指明当前事务卡在哪条 SQL、哪个索引、哪一行(或哪个间隙); - 对比两个事务的
HOLDS THE LOCK(S)和WAITING FOR THIS LOCK,能还原出谁先锁了 A 等 B,谁先锁了 B 等 A; - 如果看到
lock_mode X locks gap before rec,基本确认是间隙锁冲突,得检查 WHERE 条件是否可优化为等值查询,或补充索引缩小扫描范围。
真正难处理的,从来不是“怎么让 MySQL 不死锁”,而是“怎么让应用每次加锁都走同一条路径”。锁顺序一旦散落在不同微服务、不同线程池、不同 ORM 层抽象里,靠 DBA 单点优化几乎无效。











