MySQL InnoDB 如何检测死锁、判定死锁、处理死锁

MySQL InnoDB 如何检测死锁、判定死锁、处理死锁

环境:InnoDB引擎,死锁只发生在行锁等待,表锁MyISAM没有死锁检测。

一、核心:死锁检测算法 ------ 等待图(wait‑for graph)

InnoDB 内部维护一张锁等待图

  • 节点:每一个事务
  • 边:事务A → 事务B,代表:A在等待B持有的锁

死锁判定逻辑:

在等待图中,如果存在环(循环回路) ,就判定发生死锁。

A等B,B等C,C等A,形成环路 → 死锁。

两个关键概念区分

  1. 锁等待 :A等B,无环,只是普通等待,不会报死锁,会等待直到锁释放,或者超过innodb_lock_wait_timeout(默认50秒)报锁等待超时。
  2. 死锁 :等待图出现环路,不是超时,是检测算法主动识别出来

⚠️注意:死锁 ≠ 锁等待超时。超时是等太久拿不到锁;死锁是检测到循环等待,立刻处理。

二、检测时机

每当一个事务要等待某把锁的时候,InnoDB就触发死锁检测:

  1. 事务执行 update / delete / select for update,申请行锁;
  2. 锁被别的事务占有,本事务需要进入等待队列;
  3. 此时触发死锁检测,遍历等待图,检查有没有环路

死锁检测会消耗CPU,并发极高场景,大量事务等待锁,检测会带来性能损耗。

参数 innodb_deadlock_detect 可以关闭死锁检测,关闭后不会识别死锁,死锁事务只会全部等待直到锁等待超时

三、死锁发生后:InnoDB怎么做(牺牲策略)

检测出死锁环路之后,InnoDB不会让所有事务无限挂起,选择一个代价最小的事务作为牺牲者回滚

选择标准:undo log回滚量最小的事务,回滚这个事务,打破等待环。

  1. 被选中回滚的事务:直接回滚,抛出死锁异常
  2. 其他参与死锁的事务:继续执行,继续等待锁。

MySQL返回给应用层的异常

复制代码
Error 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

错误码:1213,SQLSTATE 40001 ,这就是死锁异常。

业务捕获这个异常,标准做法:做重试。
对比锁等待超时异常:

Error 1205: Lock wait timeout exceeded; try restarting transaction

错误码1205,是等待锁超时,不是死锁。

四、死锁日志记录

死锁发生时,最近一次死锁信息保存在内存中:

sql 复制代码
show engine innodb status;

找到 LATEST DETECTED DEADLOCK 块,里面打印:

  • 两个事务分别执行什么SQL
  • 各自持有什么锁、等待什么锁
  • 哪一个事务被选为牺牲者回滚

开启参数 innodb_print_all_deadlocks=ON,死锁信息同时写入MySQL错误日志,防止新死锁覆盖内存里的死锁记录。

注意:show engine innodb status 只保存最近一次死锁,新死锁会覆盖旧的。

五、关键点梳理

  1. 怎么判断死锁?

    InnoDB维护事务锁等待图,当事务申请锁发生等待时,遍历等待图,发现循环等待环路,判定死锁。

  2. 死锁是超时发现的吗?

    ❌不是。死锁是主动图检测发现 ;超时是参数innodb_lock_wait_timeout控制普通锁等待。就算时间很短,只要出现环路立刻判定死锁。

  3. 发生死锁后,全部事务回滚吗?

    ❌不会。只回滚代价最小的那一个事务,其余事务继续等待锁。

  4. 关闭死锁检测会怎样?

    innodb_deadlock_detect=off,不再做图检测;出现死锁时所有事务互相卡住,直到锁等待超时抛出1205错误。高并发热点行场景,有些公司会关闭检测,靠业务重试。

  5. 应用拿到什么异常?

    1213 Deadlock found when trying to get lock; try restarting transaction,业务捕获该异常进行重试。

六、简单流程总结

  1. T1持有锁A,等待锁B;T2持有锁B,等待锁A;
  2. T2申请锁A时,进入锁等待,触发死锁检测;
  3. 扫描等待图发现环路,判定死锁;
  4. 选undo量小的事务回滚;
  5. 被回滚的客户端收到1213死锁异常;
  6. 死锁现场写入innodb status日志。

补充:代码层面现象

Java中JDBC遇到死锁,会抛出SQLTransactionRollbackException,错误码1213;

业务代码捕获该异常,做有限次数重试,是标准处理方案。

相关推荐
浪子明X1 小时前
从 MongoDB 文档到关系模型:构建可重跑、可对账的数据迁移流水线
数据库·mongodb·oracle
杜子不疼.1 小时前
国产数据库撑起固井软件自主化:金仓 × 中海油服「海恒 Cemsol」落地解析
数据库
隔窗听雨眠1 小时前
GBase 8s并发控制深度解析:封锁机制、隔离级别与死锁处理全攻略
服务器·数据库·oracle
刀客Doc2 小时前
即时零售不只是多一个渠道,品牌开始重做终端生意
大数据·数据库
就叫飞六吧2 小时前
防抖、幂等、唯一约束三件套 ;
数据库
神奇霸王龙2 小时前
Agent 准入门控屠夫:5 旗舰 4 维度评估
linux·运维·数据库·ai·ai作画·agent·ai编程
鲸采云SRM采购管理系统3 小时前
采购管理系统哪家好?2026最新测评对比
java·服务器·数据库
cfm_29143 小时前
基于Binlog实现不停机数据库平滑迁移技术
运维·数据库·架构
Full Stack Developme3 小时前
SQL 注入 的历史及设计工作原理
数据库·sql