665 字
3 分钟
MySQL 8.0 如何定位并处理 InnoDB 死锁
  1. 1MySQL 面试复习导读:知识地图与阅读路线
  2. 2MySQL 存储引擎怎么选:InnoDB、MyISAM 与 MEMORY
  3. 3MySQL 索引类型与 B+ 树:结构、分类和失效场景
  4. 4MySQL B+ 树查询全过程:从根节点到页目录
  5. 5InnoDB 聚簇索引与二级索引:什么是回表
  6. 6MySQL 覆盖索引:如何避免回表
  7. 7MySQL 联合索引的最左前缀匹配原则
  8. 8MySQL 索引下推:把过滤提前到存储引擎
  9. 9MySQL 事务异常读:脏读、不可重复读与幻读
  10. 10MySQL 四种事务隔离级别与选型取舍
  11. 11MySQL MVCC:Undo Log、版本链与 ReadView
  12. 12MySQL InnoDB 锁的分类:行锁、表锁与意向锁
  13. 13MySQL 乐观锁与悲观锁:冲突少时重试,冲突多时排队
  14. 14MySQL 发生死锁怎么办:检测、定位与处理
  15. 15MySQL 事务的 ACID 特性分别是什么
  16. 16InnoDB Redo Log 如何保证崩溃恢复
  17. 17InnoDB Undo Log 的回滚与 MVCC 作用
  18. 18MySQL Binlog 是什么,和 Redo Log 有什么区别
  19. 19一条 MySQL 查询从连接到返回结果经历什么
  20. 20如何用 EXPLAIN 读懂 MySQL 执行计划
  21. 21MySQL 为什么需要 Redo Log 与 Binlog 两阶段提交
  22. 22MySQL 崩溃后如何恢复已提交事务
  23. 23InnoDB Buffer Pool 如何提升查询与写入性能
  24. 24联合索引应该如何设计
  25. 25InnoDB 快照读与当前读如何处理幻读
  26. 26联合索引范围条件之后的列还能使用吗
  27. 27MySQL 索引看起来失效了,如何判断优化器的选择
  28. 28MySQL 8.0 如何定位并处理 InnoDB 死锁本文
  29. 29MySQL 慢查询如何定位和优化
  30. 30MySQL 的 ORDER BY、GROUP BY 与 filesort
  31. 31MySQL 普通索引和唯一索引如何选择
  32. 32MySQL 主从复制的基本流程是什么
  33. 33MySQL 主从延迟和读写分离如何处理
  34. 34MySQL 深分页为什么慢,如何改写
  35. 35InnoDB 主键应该如何设计
  36. 36MySQL 字符集与排序规则有什么区别
  37. 37数据库范式与反范式如何取舍

死锁是事务间形成等待环:每个事务等待另一个事务持有的锁,单纯等待无法自行推进。InnoDB 通常检测到环后选择一个事务作为牺牲者回滚;应用仍需捕获死锁错误,并在事务边界安全重试。先区分死锁和普通锁等待超时:超时表示等待超过配置期限,不一定存在环;扩大 timeout 不能消除死锁。

可用两个连接复现:A 先锁 id=1 再请求 id=2;B 先锁 id=2 再请求 id=1。当双方各持有一个锁并等待对方时,就形成环。常见根因是事务按不同顺序更新多行、事务过长或索引不足导致扫描锁范围扩大。

第一步查看最近死锁详情:

SHOW ENGINE INNODB STATUS\G

在 LATEST DETECTED DEADLOCK 中检查两个事务的 SQL、锁模式、等待索引记录、被回滚事务及索引名。该区域通常只保留最近一次死锁,事件发生后应尽快采集;必要时评估 innodb_print_all_deadlocks 将死锁记录写入错误日志。SHOW ENGINE 输出需结合当时事务状态,不能只看最终报错 SQL。

等待中的锁可从 MySQL 8.0 Performance Schema 关联查看(需要有相应权限):

SELECT
w.REQUESTING_ENGINE_TRANSACTION_ID AS waiting_trx,
rt.PROCESSLIST_ID AS waiting_pid,
r.OBJECT_SCHEMA, r.OBJECT_NAME, r.INDEX_NAME,
r.LOCK_MODE AS waiting_mode, r.LOCK_DATA AS waiting_data,
w.BLOCKING_ENGINE_TRANSACTION_ID AS blocking_trx,
bt.PROCESSLIST_ID AS blocking_pid,
b.LOCK_MODE AS blocking_mode, b.LOCK_DATA AS blocking_data
FROM performance_schema.data_lock_waits AS w
JOIN performance_schema.data_locks AS r
ON r.ENGINE_LOCK_ID = w.REQUESTING_ENGINE_LOCK_ID
JOIN performance_schema.data_locks AS b
ON b.ENGINE_LOCK_ID = w.BLOCKING_ENGINE_LOCK_ID
LEFT JOIN performance_schema.threads AS rt
ON rt.THREAD_ID = r.THREAD_ID
LEFT JOIN performance_schema.threads AS bt
ON bt.THREAD_ID = b.THREAD_ID;

data_lock_waits 描述请求锁与阻塞锁关系,data_locks 展示锁对象和模式;这反映当前等待,不是已结束死锁的历史档案。诊断流程是保存现场、识别等待环和 SQL、检查索引与锁范围、统一多行访问顺序并缩短事务,然后压测验证。不要不加判断地 KILL 连接;终止连接会触发回滚且可能扩大业务影响。

追问#

SHOW ENGINE INNODB STATUS 为什么查不到刚才的死锁?#

它主要显示最近检测到的死锁,后续死锁可能覆盖记录;应及时采集,或评估记录所有死锁到错误日志。

data_lock_waits 能否查询过去的死锁?#

不能作为历史审计表;它用于观察当前锁等待。历史现场需依赖 InnoDB 状态输出、错误日志或外部监控采集。

代码怎么降低死锁概率?#

让事务按统一顺序访问多行、缩短事务、为过滤条件建立合适索引,并对死锁受害事务做有限且幂等的重试。

MySQL 8.0 如何定位并处理 InnoDB 死锁
https://blog.xqcherry.top/posts/interview/mysql/mysql-deadlock-diagnosis-example/
作者
xqcherry
发布于
2026-10-12
许可协议
CC BY-NC-SA 4.0