必须立刻执行show engine innodb status\g,因死锁日志仅驻留内存且只保留最近一次;搜不到latest detected deadlock主因是新死锁覆盖、mysql重启或未及时执行,需秒级响应并交叉比对两事务的waiting与holds锁信息及lock_mode类型。

必须立刻执行 SHOW ENGINE INNODB STATUS\G,否则死锁日志就没了——它只驻留在内存里,且仅保留最近一次。
为什么刚执行完就搜不到 LATEST DETECTED DEADLOCK
这不是命令没用,而是日志已被覆盖或丢失。常见原因有三个:
- 执行
SHOW ENGINE INNODB STATUS\G前,又发生了新死锁,旧记录被冲掉 - MySQL 服务重启过,该信息不持久,重启即清空
- 业务报错
ERROR 1213 (40001): Deadlock found when trying to get lock后没立即查,等了几秒再查,已经晚了
别去 TRANSACTIONS 或 SEMAPHORES 段翻找——那些是当前状态,和已回滚的死锁无关。
怎么快速定位并交叉比对两个事务的锁关系
找到 ------------------------ LATEST DETECTED DEADLOCK ------------------------ 后,重点盯住两组字段:
- 每个事务块以
*** (1) TRANSACTION:和*** (2) TRANSACTION:开头,编号不代表执行顺序,只是标记 - 在事务 (1) 里找
WAITING FOR THIS LOCK TO BE GRANTED,记下索引名、space id、page no、heap no - 在事务 (2) 里找
HOLDS THE LOCK(S),看它是否持有完全相同的索引 + page + heap(或同一间隙) - 如果 (1) 等的是 (2) 持有的资源,且 (2) 等的又是 (1) 持有的资源,闭环成立
例如:事务 (1) WAITING FOR index `PRIMARY` of table `test`.`users`,page no 3;事务 (2) HOLDS THE LOCK(S) 正是同一索引、同一 page、不同 heap no 的 lock_mode X locks rec but not gap ——这就是死锁铁证。
从 lock_mode 判断锁类型,避免误判索引失效
lock_mode 字段直接暴露锁行为,不能只看 SQL 表面:
-
lock_mode X locks rec but not gap:精确匹配主键/唯一索引,比如WHERE id = 1,说明走了索引 -
lock_mode X locks gap before rec:间隙锁,常见于WHERE a > 5或唯一键冲突检查,RR 隔离级别下极易引发隐蔽死锁 -
lock_mode X locks gap before rec insert intention:插入意向锁,典型出现在INSERT ... SELECT或并发INSERT场景 - 日志里出现
GEN_CLUST_INDEX:说明表没显式主键,InnoDB 自建隐式聚簇索引,得立刻补主键
看到 SQL 是 WHERE email = ? 却锁在 idx_name 上?大概率是字段类型不匹配、用了函数(如 LOWER(email)),或 OR 导致索引失效——必须结合 EXPLAIN 验证执行计划。
为什么光靠 STATUS 日志还不够
SHOW ENGINE INNODB STATUS\G 只给“快照”,不给上下文。容易漏掉的关键点:
- 它不告诉你事务持续了多久——查
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX看trx_started和trx_state - 它不显示谁在阻塞谁的完整链路——
performance_schema.data_lock_waits(MySQL 8.0+)能直接关联REQUESTING_TRX_ID和BLOCKING_TRX_ID - 它不展示每把锁对应的原始值——
performance_schema.data_locks会列出LOCK_DATA(比如 hex 80000001 对应十进制 1),可反推被锁的具体行 -
INFORMATION_SCHEMA.INNODB_LOCKS在 MySQL 8.0.1+ 已废弃,用它会报错,别踩坑
最常被忽略的是时间精度:2026-07-01T20:45:12.123456Z 这种微秒级时间戳,是判断并发时序、还原执行先后的关键依据,不是摆设。











