MySQL 死锁反复出现?一套从定位到根治的完整打法

举报
yd_297085602 发表于 2026/10/30 14:09:20 2026/10/30
【摘要】 生产环境数据库每隔几天报一次死锁,日志里多个事务交叉等待同一批表资源。很多同学的处置方式是调隔离级别、缩短事务,然后发现——还是死。这篇文章给一套完整的定位到根治路径,以 MySQL InnoDB 为例。先说本质:死锁不是数据库的 bug,是两个事务以相反的顺序访问同一批资源。A 先锁行 r1 再要 r2,B 先锁 r2 再要 r1,互相等待,InnoDB 检测到环后回滚其中一方。调隔离级别...

生产环境数据库每隔几天报一次死锁,日志里多个事务交叉等待同一批表资源。很多同学的处置方式是调隔离级别、缩短事务,然后发现——还是死。这篇文章给一套完整的定位到根治路径,以 MySQL InnoDB 为例。

先说本质:死锁不是数据库的 bug,是两个事务以相反的顺序访问同一批资源。A 先锁行 r1 再要 r2,B 先锁 r2 再要 r1,互相等待,InnoDB 检测到环后回滚其中一方。调隔离级别和缩短事务只是降低概率,只要"相反顺序访问"这个结构性问题还在,死锁就一定会复发。

一、第一步:让数据库把现场交出来

很多人排查死锁失败,是因为死锁现场默认只保留最近一次,而且不留全量。先把证据链建好:

第一件事,打开全量死锁日志:

SET GLOBAL innodb_print_all_deadlocks = ON;

这样每个死锁都会写进 error log,而不是只留最后一次。事后诸葛亮和全量录像,是两种排查体验。

第二件事,拿最新一次死锁现场:

SHOW ENGINE INNODB STATUS

找 LATEST DETECTED DEADLOCK 段。里面有死锁发生瞬间两个事务各自正在执行的 SQL、各自持有的锁(HOLDS THE LOCK)、各自等待的锁(WAITING FOR)、锁的模式。这就是破案的核心证据。

第三件事,运行期间主动抓堵车现场:

SELECT * FROM information_schema.INNODB_TRX ORDER BY trx_started;

看当前有哪些长事务。再看:

SELECT * FROM sys.innodb_lock_waits;

这个视图直接告诉你"谁堵谁",输出里有 blocking_pid,拿着它去 PROCESSLIST 里查,就能看到冲突 SQL 原文。比翻日志快得多。

二、第二步:读死锁日志,关键是锁模式

拿到日志后,重点看三个东西。

第一个看 lock_mode。如果看到 locks rec but not gap,这是记录锁,说明两个事务按不同顺序更新同一批行,根治方向是统一访问顺序。如果看到 locks gap before rec 或者 insert intention waiting,这是间隙锁冲突,典型场景是 RR 隔离级别下范围 UPDATE 和 INSERT 打架,根治方向是收窄范围或者降隔离级别。如果看到表级 IX 锁和记录锁混合出现,多半是缺索引导致扫描范围放大

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。