直接看死锁日志就能定位根源,核心抓三点:事务执行顺序、锁类型(行锁/间隙锁/意向锁)、资源路径(具体表、索引、行条件);通过SHOW ENGINE INNODB STATUS\G查看LATEST DETECTED DEADLOCK,分析时间戳、两个事务的HOLDS/WAITING锁信息、SQL原文及ROLL BACK标识,再比对操作顺序、检查索引有效性、确认隔离级别影响,结合Java层统一访问顺序、拆分长事务、开启innodb_print_all_deadlocks实现根治。

直接看死锁日志就能定位根源,重点不是“有没有报错”,而是“能不能读透”——核心抓三点:事务执行顺序、锁类型(行锁/间隙锁/意向锁)、资源路径(具体表、索引、行条件)。
怎么看懂死锁日志
在 MySQL 客户端执行:
SHOW ENGINE INNODB STATUS\G
找到 LATEST DETECTED DEADLOCK 模块,它是一份结构化事故报告:
-
时间戳:如
2026-07-28 15:22:34,可对齐应用日志查业务上下文 -
两个事务块:标为
TRANSACTION 12345和TRANSACTION 67890,每块含:-
HOLDS THE LOCK(S):已持锁,例如X lock on index `PRIMARY` of table `db.order`, id=1001 -
WAITING FOR THIS LOCK:正等待锁,例如X lock on index `idx_user_id` of table `db.account`, where user_id=2002
-
-
SQL 原文:每个事务末尾列出触发锁的语句,如
UPDATE order SET status='paid' WHERE id=1001,这是还原业务逻辑的关键 -
ROLLING BACK 行:MySQL 自动选中的牺牲者,如
WE ROLL BACK TRANSACTION 12345
三步锁定根本原因
别只关注“谁被回滚了”,要顺藤摸瓜找冲突链:
-
比对操作顺序:看事务 A 先锁
order再等account,事务 B 是否反过来先锁account再等order?这是最常见也最易修复的“顺序不一致” -
检查索引有效性:若
WAITING FOR显示锁的是GEN_CLUST_INDEX或未指定具体行,大概率是UPDATE/DELETE未命中索引,导致升级为表锁或间隙锁扩大范围 -
确认隔离级别影响:在
REPEATABLE READ下,SELECT ... FOR UPDATE或范围条件(如WHERE amount > 100)会隐式加间隙锁,可能把本不该锁的记录也圈进来
Java 侧快速落地的解决办法
数据库配置调优只是辅助,真正见效快的是代码层控制:
立即学习“Java免费学习笔记(深入)”;
-
强制统一资源访问顺序:比如所有转账类操作,约定必须先更新
account表(按user_id升序),再更新order表(按order_id升序)。可用工具类封装排序逻辑,避免人工出错 - 拆分长事务:事务中避免远程调用、复杂计算、日志打印等非数据库操作;把大事务拆成多个小事务,减少单次锁定资源量和持有时间
-
开启全量死锁日志:在
my.cnf中配置innodb_print_all_deadlocks = 1,配合应用层埋点与监控告警,实现主动防控


















