立即执行 SHOW ENGINE INNODB STATUS\G 并定位 LATEST DETECTED DEADLOCK 区块,聚焦两个事务的 HOLD/WAIT 锁信息、SQL 语句及回滚决策,结合锁模式反推根因(如间隙锁、隐式主键、索引未命中),并开启 innodb_print_all_deadlocks 持续落盘分析。

MySQL 生产环境遇到死锁,第一反应不是重试或重启,而是立刻执行 SHOW ENGINE INNODB STATUS\G 拿到现场快照——它能直接暴露两个事务如何互相卡住,是定位根因最快速、最权威的手段。
立即执行并精准定位死锁区块
命令必须加 \G 格式化输出,否则信息挤成一行无法阅读。执行后,在终端中搜索:
------------------------ LATEST DETECTED DEADLOCK ------------------------- 只关注这个区块内容,其他部分(如 TRANSACTIONS、SEMAPHORES)与本次死锁无关
- 该区块只保留最近一次死锁,若刚发生就被新死锁覆盖,或 MySQL 重启过,则查不到——说明需配合日志落盘
重点看两个事务块里的四类关键信息
区块内以 *** (1) TRANSACTION: 和 *** (2) TRANSACTION: 开头,分别代表冲突双方。交叉比对以下四点:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
-
HOLDS THE LOCK(S):这个事务当前「攥着什么」——记下锁在哪个索引(如
index `idx_order_status`)、哪张表、是否为间隙锁(含gap before rec即属高风险) - WAITING FOR THIS LOCK TO BE GRANTED:它「卡在哪条 SQL」,等的是另一个事务持有的锁,必须和对方的 HOLDS 对得上才构成闭环
-
末尾的 SQL 语句:如
UPDATE orders SET status = 'shipped' WHERE order_id = 1001,这是映射到业务逻辑的唯一锚点 - WE ROLL BACK TRANSACTION (1):明确指出哪个事务被回滚(通常是 undo log 小的那个),帮助判断代价倾向
从锁描述反推真实问题类型
日志里的锁模式不是术语堆砌,而是直接指向根因:
-
lock_mode X locks rec but not gap→ 纯行锁,大概率是多表更新顺序不一致 -
lock_mode X locks gap before rec→ 间隙锁,常见于范围查询(如WHERE price BETWEEN 100 AND 300)或唯一键冲突检查,不是“没加索引”就能解决 -
index `GEN_CLUST_INDEX`→ 表无显式主键,InnoDB 使用隐式聚簇索引,应优先补主键 - 锁落在非预期索引(如业务查
user_id却锁了GEN_CLUST_INDEX)→ 基本确认 WHERE 条件未命中索引,需检查类型转换、函数包裹或 OR 条件
高频死锁必须开启全量日志落盘
仅靠 SHOW ENGINE INNODB STATUS 不足以支撑持续分析:
- 临时启用:
SET GLOBAL innodb_print_all_deadlocks = ON; - 永久生效:在
my.cnf的[mysqld]段添加两行:innodb_print_all_deadlocks = 1log_error = /var/log/mysql/error.log - 开启后每次死锁都会追加进 error log,便于批量识别模式(例如多个事务总在
users和orders表之间交叉更新) - 注意日志轮转,避免撑爆磁盘

















