死锁日志怎么读
死锁不是故障,而是并发控制机制的主动止损:两个及以上事务循环等待对方持有的锁,数据库挑选代价较小的一方回滚,让其他事务继续推进。状态输出里保留最近一次死锁现场,包含两个事务正在执行的语句、各自持有的锁与正在等待的锁,以及被回滚的是哪一方。读它的目的是找到访问顺序上的冲突点,而不是找出「谁的错」。
基本信息
| 适用平台 | MySQL 8.0(InnoDB) |
|---|---|
| 查看方式 | 查看引擎状态,输出中定位最近一次死锁的段落 |
| 保留范围 | 默认只保留最近一次,需打开专门开关才能记录全部 |
| 被回滚方 | 引擎选择代价较小的事务回滚,属于正常机制 |
| 应用要求 | 捕获死锁错误后回滚并重试整个事务 |
典型使用场景
- 线上偶发报错排查:确认是否真的发生死锁以及涉及哪两条语句
- 批量任务与在线业务互撞:定位哪一类的访问模式在制造循环等待
- 上线前验证:把新增语句放进状态观察,看是否引入新的等待关系
- 统计死锁频率:评估是否需要对访问顺序做统一规范
- 复盘事故:把被回滚事务的语句与业务动作对应起来
查看与记录
查看与记录
-- 查看引擎状态,在输出中定位最近一次死锁段落
SHOW ENGINE INNODB STATUS;
-- 关注三块内容:
-- 两个事务各自的语句、持有的锁与等待的锁
-- 输出末尾会说明回滚了哪一方
-- 若出现等待关系成环,即构成死锁
-- 排查期打开开关,把每次死锁都写入错误日志
SET GLOBAL innodb_print_all_deadlocks = ON;
-- 结合锁信息表定位当前正在等待的锁
SELECT * FROM performance_schema.data_locks;
SELECT * FROM performance_schema.data_lock_waits;
-- 排查结束后记得关闭,避免日志量持续增长
SET GLOBAL innodb_print_all_deadlocks = OFF;输出段读法
| 内容块 | 说明 | 用它做什么 |
|---|---|---|
| 事务语句 | 参与死锁的双方正在执行的语句 | 定位业务代码与访问路径 |
| 持有锁列表 | 每个事务已拿到的锁 | 找到冲突的键与区间 |
| 等待锁列表 | 每个事务正在等待的锁 | 看出等待关系如何成环 |
| 回滚标记 | 指明被牺牲的事务 | 确认应用需要从哪一步重试 |
| 记录范围 | 默认仅最近一次 | 历史多次排查需打开全量记录开关 |
多数死锁的根因在应用访问行为上:同一批数据在不同代码路径里被按不同顺序更新,或者一次事务里锁了过多行。统一加锁顺序、缩短事务范围,比在数据库层调参数有效得多。
把死锁当成需要彻底消灭的对象会走进误区:只要存在并发写入,死锁就可能发生。正确的目标是让应用能接住它并重试,同时把发生频率控制在可接受范围。