死锁是并发逻辑缺陷的信号,根因在于加锁顺序不一致、索引缺失或间隙锁失控;通过SHOW ENGINE INNODB STATUS可查最近死锁详情,重点分析LATEST DETECTED DEADLOCK区块中被回滚事务、锁模式及锁住的具体记录。

死锁不是数据库故障,而是并发逻辑缺陷的信号——只要事务加锁顺序不一致、索引缺失或间隙锁范围失控,就一定会复现。MySQL 8.0 的 innodb_print_all_deadlocks = ON 和 performance_schema.data_locks 已足够定位根因,关键在能否从日志里读出「谁锁了什么、为什么锁、为什么等不到」。
怎么看最近一次死锁详情(SHOW ENGINE INNODB STATUS\G)
这是最直接的入口,但很多人只扫一眼就放弃。真正有用的线索藏在 LATEST DETECTED DEADLOCK 区块里:
- 先找被回滚的事务(
ROLLING BACK行),它通常是持有锁最少的那个,不代表它是“问题方” - 对比两个事务的
mysql thread id和trx_id,再结合information_schema.INNODB_TRX查它们的启动时间、SQL、事务状态 - 重点看每条 SQL 后面的
lock_mode X locks rec but not gap或lock_mode X locks gap before rec——前者是精准行锁,后者是间隙锁,后者更容易引发交叉冲突 - 注意
lock struct(s)下的lock_trx_id和lock_rec_lock,能确认锁住的具体索引和记录值(比如PRIMARY, 123或idx_name, 'Eason')
怎么查当前锁等待链(sys.innodb_lock_waits)
当死锁已发生但还没被检测到(比如刚卡住几秒),或者想确认是否正在形成循环等待,这个视图比手写 JOIN 更可靠:
-
waiting_trx_id和blocking_trx_id是核心,直接对应两个事务 ID -
waiting_pid和blocking_pid是线程 ID,可立刻用KILL终止阻塞源(慎用,优先查清业务逻辑) -
waiting_query显示卡住的 SQL,常含FOR UPDATE或UPDATE ... WHERE;blocking_query往往是更早执行、尚未提交的语句 - 如果返回空,不代表没锁——可能只是没形成等待链,需进一步查
performance_schema.data_locks
怎么验证是不是索引失效导致锁扩大(EXPLAIN + data_locks)
90% 的死锁根源不在并发本身,而在一条本该走索引却全表扫描的 SQL。它会让 UPDATE 锁住成百上千行,大幅提高冲突概率:
- 对报错 SQL 执行
EXPLAIN,重点看type是否为ALL或index,key是否为NULL,rows是否远超预期 - 再查
performance_schema.data_locks,过滤LOCK_TYPE = 'RECORD'且LOCK_DATA大量重复或跨度极大(如从 1 到 5000) - 常见诱因:
WHERE条件用了函数(DATE(create_time))、隐式类型转换(phone = 13800138000)、OR中混入非索引列、联表条件未走索引
怎么确认事务加锁顺序是否一致(INNODB_TRX + 业务代码回溯)
交叉加锁是最常见的死锁成因,但仅靠日志无法还原完整路径,必须结合业务调用栈:
- 从
INNODB_TRX中提取trx_started、trx_state、trx_query,按时间排序,观察多个事务是否在相同表上以不同顺序执行UPDATE或SELECT FOR UPDATE - 检查 ORM 层(如 MyBatis XML、GORM 链式调用)中 SQL 的 where 条件顺序是否动态拼接、是否受参数影响而改变字段顺序
- 特别注意批量更新(
UPDATE ... WHERE id IN (..))与单行更新(UPDATE ... WHERE order_id = ?)并发时,InnoDB 内部加锁顺序依赖索引 B+ 树遍历路径,而非 SQL 字面顺序 - 若涉及多表,统一约定操作顺序:例如所有事务都先
UPDATE orders再UPDATE order_items,禁止反向操作
真实线上环境里,data_locks 的 LOCK_DATA 字段可能显示为 NULL 或截断值,此时必须结合索引定义和 WHERE 条件反推实际锁定范围;另外,innodb_print_all_deadlocks = ON 会把每次死锁写入错误日志,但日志轮转策略若太激进,可能刚排查完就丢失了原始上下文——建议搭配自动监控脚本实时捕获 SHOW ENGINE INNODB STATUS\G 快照。


















