必须立刻执行SHOW ENGINE INNODB STATUS\G,因死锁日志仅驻留内存且仅保留最近一次;找不到LATEST DETECTED DEADLOCK,说明已被覆盖、未发生死锁或MySQL重启导致丢失,需结合错误日志及innodb_print_all_deadlocks配置排查。

必须立刻执行 SHOW ENGINE INNODB STATUS\G,否则死锁现场就没了——它只保留在内存里,且仅存最近一次。
为什么执行完命令却找不到 LATEST DETECTED DEADLOCK?
不是命令错了,而是死锁日志已被覆盖或根本没发生:
- 延迟哪怕 2 秒再执行,新死锁一触发,旧记录就被清掉
- MySQL 重启后该段内容不持久,直接消失
- 应用报的是
Lock wait timeout exceeded而非Deadlock found when trying to get lock,说明只是锁等待超时,不是死锁 - 云数据库(如阿里云 RDS、腾讯云 CDB)默认关闭
innodb_print_all_deadlocks,SHOW ENGINE拿不到历史死锁,只能靠错误日志
怎样从输出里三秒定位死锁闭环?
全文只盯一个区域:LATEST DETECTED DEADLOCK。它下面只有两个事务块,编号 (1) 和 (2) 不代表时间先后,只是标记区分:
- 在 *** (1) TRANSACTION 块里,找
HOLDS THE LOCK(S)—— 看它攥着哪个索引、哪页(page no)、什么锁模式(如X locks rec but not gap) - 在 *** (2) TRANSACTION 块里,找
WAITING FOR THIS LOCK TO BE GRANTED—— 如果等的也是同一个index+ 同一个page no,闭环成立 - 特别注意
lock_mode X locks gap before rec:这是间隙锁,常见于WHERE status IN (1,2)或无主键表上的隐式聚簇索引GEN_CLUST_INDEX,比行锁更隐蔽
看到 SQL 却修不好?多半是索引没走对
trx_query 显示的是事务中“最后执行的一句”,但它是否真命中索引、有没有被优化器绕开,得反推:
- 对同一条 SQL 执行
EXPLAIN,检查type是否为ALL、key是否为空 - 日志里锁在
index `idx_email`,但你的 WHERE 条件却是name = ?→ 很可能字段类型不匹配,或用了函数(如UPPER(email)),导致索引失效 - 没定义主键的表,InnoDB 会建隐式聚簇索引
GEN_CLUST_INDEX,日志里出现这个名,先跑SHOW CREATE TABLE确认结构 -
INSERT INTO SELECT场景下,若看到WAITING FOR ... insert intention,说明两个事务在抢同一段间隙,不是数据冲突,是插入并发控制机制本身在起作用
真正容易被忽略的是:死锁日志里展示的锁关系,是 InnoDB 在回滚前最后一刻抓取的快照;你看到的 ROLLING BACK TRANSACTION (2) 是结果,不是过程。修复重点不在“谁先谁后”,而在两个事务加锁的**顺序是否一致**、**索引是否生效**、**隔离级别是否放大了锁范围**——这些细节一旦错位,哪怕 SQL 看似一样,也会在高并发下反复死锁。


















