MySQL 死锁日志怎么还原现场:LATEST DETECTED DEADLOCK、锁顺序与最小复现
线上出现 ERROR 1213 (40001): Deadlock found when trying to get lock 时,单看这一行只能知道事务被回滚了,无法解释是谁先拿了哪把锁。真正有价值的现场通常在 InnoDB 的 LATEST DETECTED DEADLOCK 记录里:它会列出两个事务持有的锁、正在等待的锁,以及最后被回滚的事务。先把这段记录还原成“事务—资源—等待”的闭环,再决定是调整访问顺序、缩短事务,还是只在应用层重试。
要点速览
SHOW ENGINE INNODB STATUS的死锁段落要成对阅读,不能只看最后一行。- 持有锁和等待锁拼成环,才是死锁;单向等待通常只是锁竞争。
- 用两条事务按相反顺序更新 row A、row B,可以稳定复现最小问题。
- 修复优先统一资源访问顺序,再缩短事务范围,最后为可重试错误设计退避。
先把死锁日志读成一张关系表
直接在复现环境或者故障发生的窗口期执行对应操作:
SHOW ENGINE INNODB STATUS\G
输出中的 LATEST DETECTED DEADLOCK 通常包含两个 TRANSACTION 段。每段先描述当前事务已经持有什么,再描述它正在等待什么。不要把 “WAITING FOR THIS LOCK” 误读成事务已经拿到的锁;还原时应把它拆成四列:
| 字段 | 要确认的信息 | 对应现场含义 |
|---|---|---|
| TRANSACTION | 对应哪个连接/线程 | 快速定位背后的业务请求或后台任务 |
| HOLDS THE LOCK(S) | 它已经占住了什么资源 | 梳理它阻塞其他请求的资源范围 |
| WAITING FOR THIS LOCK | 它还想拿到什么锁 | 指向另一个事务当前持有的资源 |
| WE ROLL BACK TRANSACTION | 谁被选中回滚 | 明确本次死锁的直接处理结果 |

实际排查的时候先记下事务编号、线程 ID、表名和索引名,再回到应用日志对应时间窗口里找对应的请求参数。死锁日志里出现相同表名不代表锁冲突已经成立,必须确认一个事务在等的记录,刚好是另一个事务已经持有的资源。
什么时候是死锁,什么时候只是锁等待
普通锁等待只有单向指向:T1 等 T2 释放锁就可以继续。死锁则至少形成一个闭环:T1 持有 row A、等待 row B;T2 持有 row B、等待 row A。InnoDB 检测到这个环之后会选一个事务回滚,让另一个事务可以正常提交。
你可以把日志内容直接整理写在便签或者工单里,对应画出两条事务的资源持有和等待链路:
T1 holds A, waits B
T2 holds B, waits A
=> T1 -> T2 -> T1
如果只能写出 T1 -> T2,那更像是普通锁竞争,应该继续看事务是否长时间未提交、是否被慢查询或网络调用拖住。这个区别会直接影响处理方式:等待问题先缩短占锁时间,闭环问题还要打破访问顺序。
用相反锁顺序构造最小复现
先准备一张只有两行的测试表,同时开两个独立的数据库会话,不要用同一个连接:
CREATE TABLE deadlock_demo (
id BIGINT PRIMARY KEY,
balance INT NOT NULL
) ENGINE=InnoDB;
INSERT INTO deadlock_demo (id, balance)
VALUES (1, 100), (2, 100);
会话 A 先锁住 ID 为 1 的行,之后请求 ID 为 2 的行时会进入等待:
START TRANSACTION;
UPDATE deadlock_demo SET balance = balance + 10 WHERE id = 1;
-- 暂停,等待会话 B 先锁住 id=2
UPDATE deadlock_demo SET balance = balance - 10 WHERE id = 2;
会话 B 反过来先锁住 ID 为 2 的行,再请求 ID 为 1 的行,就刚好拼成死锁环:
START TRANSACTION;
UPDATE deadlock_demo SET balance = balance + 20 WHERE id = 2;
UPDATE deadlock_demo SET balance = balance - 20 WHERE id = 1;

第二个 UPDATE 会让两个会话互相等待,最终一个连接收到 1213。复现时不要把两个 SQL 放在同一连接,也不要让客户端自动提交;否则锁不会跨语句保持,现场就不稳定。
修复优先级:先统一顺序,再控制事务长度
最容易验证生效的修复方案,就是让同一类业务流程始终按固定顺序访问资源:比如转账场景里,不管资金往哪个方向走,都先锁 ID 更小的账户,再锁 ID 更大的账户。这样两个事务最多只会排队等锁,不会因为加锁顺序相反而形成环。
- 统一访问顺序:批量更新、转账、库存扣减这类场景,都先把要操作的资源 ID 排序之后再依次加锁。
- 缩短事务时长:不要在持有行锁的过程中调用远程接口、等待用户输入或者执行大批量计算。
- 缩小锁范围:保证更新语句的索引可以精准命中目标行,避免因为查询条件不全锁住远大于预期的记录范围。
- 应用端重试:只对明确抛出的 1213/40001 错误做有限次数重试,每次重试都重新开启完整事务,搭配合理的退避时长,不能复用已经失败的连接状态继续执行。
重试只是最后一道兜底恢复措施,不能替代前期的锁顺序设计。如果每次事务还是以相反顺序加锁,重试只会把锁冲突推迟到下一轮,没法从根源解决问题。
用验收清单确认修复没有换来新问题
修复完成后至少做三组验证:相同并发压力下不再出现锁等待闭环;事务提交前没有额外的跨网络远程调用等待;出现普通锁等待时,等待时长和持锁时长都在预设的可接受范围内。测试记录里要保留SQL执行顺序、并发连接数、死锁回滚次数、平均事务耗时和最长锁等待时间这些信息。
如果线上已经发生过死锁,建议同时存一份脱敏后的 InnoDB 状态片段和对应时间段的请求日志。后续再出现同类问题时,先比对资源访问顺序是否符合之前的修复要求,再判断是不是新上线的索引或者批量任务引入了其他的加锁路径。
常见问题
死锁一定说明 MySQL 配置错了吗?
不一定。绝大多数死锁都是不同业务事务以相反顺序访问同一组行造成的,数据库自动检测并回滚是自带的正常保护机制,先优先检查锁访问顺序和事务边界配置。
为什么只看到一个事务被回滚?
InnoDB 会选择修改行数更少、回滚代价更小的事务来回滚,打破等待闭环,剩下另一个事务继续执行。所以应用层必须把 1213 错误当成一次完整的事务失败来处理,不能认为只有部分操作没执行。
捕获 1213 后能不能只重试最后一条 SQL?
不能直接在当前会话继续往下执行。触发死锁的原事务已经被完整回滚,应该重新开启新事务,重新读取需要的最新数据,按修复后的加锁顺序执行全部业务步骤。
SHOW ENGINE INNODB STATUS 的死锁记录会保留多久?
这个字段展示的只是最近一次被检测到的死锁。如果要做长期问题分析,应该把这段关键输出接入故障记录或者监控采集链路,避免下一次死锁日志把上一次的现场直接覆盖掉。
还原 MySQL 死锁的核心不是死背错误码,而是把日志里每个事务的「已持有资源」和「正在等待资源」梳理成有向图。只要能明确定位出等待闭环,就可以通过统一锁顺序、短事务设计、可控重试这几个方向逐项验证修复效果。
Go 时间解析为什么在服务器上差几个小时:time.Parse、Location 与时区输入
- 上一篇
- Go 时间解析为什么在服务器上差几个小时:time.Parse、Location 与时区输入
- 下一篇
- Obsidian 图片链接失效怎么排查:附件路径、仓库设置与重建索引
-
- 数据库 · MySQL | 5小时前 |
- MySQL 8.4 authentication_policy 怎么规划账号认证:插件顺序、兼容窗口与登录验收
- 113浏览 收藏
-
- 数据库 · MySQL | 6小时前 | MySQL · InnoDB · 数据恢复 · Clone Plugin · 实例运维 · MySQL 8.4 Clone Plugin CLONE INSTANCE 实例恢复 捐赠端 接收端
- MySQL 8.4 Clone Plugin 怎么做实例级恢复:捐赠端、接收端与版本核对
- 186浏览 收藏
-
- 数据库 · MySQL | 12小时前 | MySQL · 数据库 · 权限管理 · 故障排查 · 账号安全 · 账号锁定 MySQL 8.4 FAILED_LOGIN_ATTEMPTS PASSWORD_LOCK_TIME ACCOUNT UNLOCK
- MySQL 8.4 账号锁定怎么恢复:FAILED_LOGIN_ATTEMPTS、锁定状态与解锁验收
- 494浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ljg-skills
- ljg-skills 是李继刚开源的 AI 技能与提示词集合,面向大模型使用者整理了一批可复用的 prompt、角色设定和任务技能模板,适合用于学习提示词设计、搭建个人 AI 工作流和沉淀团队常用智能体能力。
- 5250次使用
-
- MELO音乐
- MELO音乐是一站式AI视频与音乐制作助手,对标suno, udio的高品质体验。提供伴奏生成、原创写词、无损导出、哼唱识曲、混音变声等全套音频与短视频编辑工具。无论是流行Kpop、电音说唱、民谣古风、摇滚儿歌还是商用轻音乐,MELO为你免费谱曲,轻松做同款!
- 4758次使用
-
- UniScribe
- UniScribe 是一款 AI 音视频转文字与内容整理工具,支持上传音频、视频文件或粘贴 YouTube 链接,自动生成转写文本、摘要、思维导图和关键问题,并支持多格式导出,适合会议记录、课程学习、访谈整理和内容创作复盘。
- 4713次使用
-
- 剧云
- 剧云是专业中文剧本创作平台,安全稳定运行十余年,集成AI编剧、剧本医生审核、人物小传、剧情关系图、大纲编写、多人协作、Word导入导出、版权管控功能,数据安全防护,轻松高效创作剧本。
- 4964次使用
-
- 万象有声
- 万象有声,一个专为有声创作者打造的新一代智能有声内容创作平台。平台提供专业的智能拆章、智能画本编辑、AI配音、AI生成音效、后期制作、智能对轨、智能审听等有声创作全流程工具,可以帮助创作者高效、低成本创作出引人入胜的有声作品。立即体验,让有声书制作更简单!
- 4920次使用
-
- MySQL 明明加了索引,为什么查询还是很慢?先查这 6 个点
- 2026-06-27 374浏览
-
- 接口返回的数据和数据库不一致怎么办?按数据生命周期排查
- 2026-06-27 398浏览
-
- golang MySQL实现对数据库表存储获取操作示例
- 2022-12-22 499浏览
-
- golang 基于 mysql 简单实现分布式读写锁
- 2023-01-07 384浏览
-
- 详解如何利用GORM实现MySQL事务
- 2023-01-07 184浏览

