能直接确认是否存在循环死锁链的唯一可靠方式是查show engine innodb status\g输出中的latest detected deadlock区域,它必须同时包含(1) transaction和(2) transaction两段,且一段holds某锁并waiting另一锁、另一段恰好相反,形成a等b、b等a的闭环互指关系。

能直接确认是否存在循环死锁链,唯一可靠的方式是查 SHOW ENGINE INNODB STATUS\G 输出里的 LATEST DETECTED DEADLOCK 区域——它不是推测,而是 InnoDB 已经识别并打破的闭环证据。
怎么看日志里有没有真正的循环等待
死锁日志里必须同时满足两个硬条件才算闭环成立:
- 出现明确标记的
(1) TRANSACTION和(2) TRANSACTION两段 - 其中一段显示
HOLDS THE LOCK(S)某资源、WAITING FOR THIS LOCK TO BE GRANTED另一资源;另一段恰好反过来——A 持有 id=1 等 id=2,B 持有 id=2 等 id=1
如果只看到 LOCK WAIT 但没出现 LATEST DETECTED DEADLOCK 标题,说明只是单向阻塞,还没形成环。哪怕等了 30 秒也没用,InnoDB 不会把超时当死锁。
为什么 information_schema.innodb_lock_waits 不能代替死锁日志
这个视图只反映“当前谁在等谁”,但它是瞬态快照,无法体现闭环逻辑:
- 它可能只显示事务 A 等事务 B,却看不到事务 B 其实也在等事务 A(因为 B 刚被回滚或已释放锁)
- 死锁发生后,InnoDB 会立刻回滚一个事务,
innodb_lock_waits里只剩下一个“残留等待”,闭环已被破坏 - 空表并发
INSERT触发的间隙锁死锁,在该视图里甚至可能查不到任何记录——因为锁在间隙上,不对应具体行
什么时候 SHOW ENGINE INNODB STATUS 会“看不到”死锁
不是日志没记,而是你没抓准时机或配置不对:
-
innodb_deadlock_detect = OFF时,InnoDB 根本不检测,自然不会写死锁日志,只会等innodb_lock_wait_timeout超时退出 - 默认只保留最近一次死锁,如果中间又发生过一次,前一次就被覆盖了;要持久化,得配
innodb_print_all_deadlocks = 1 - 执行
SHOW ENGINE INNODB STATUS前,死锁刚被处理完,但你延迟了几秒才查——日志还在,但滚动太快容易漏掉LATEST DETECTED DEADLOCK这一行标题
闭环的本质是“互指”,不是“排队”。只要日志里没出现双向持有+双向等待的明确互指关系,就别急着下结论——那大概率只是锁等待,不是死锁。











