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;

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

相关推荐
小白男神3 天前
MySQL进阶学习四(存储过程、游标、触发器)
mysql
这个DBA有点耶3 天前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核
数据库·mysql·架构
DBA_G3 天前
从地面到云霄:GBase数据库在民航三大场景的落地实践
数据库
自由能燃气设备3 天前
商用全预混低氮冷凝锅炉免费方案vs付费方案对比+选型避坑指南
大数据·数据库·人工智能
科创致远3 天前
科创致远 ESOP 系统核心效能与实战价值展示
大数据·数据库·人工智能·精益工程
kybs19913 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
2601_962218613 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法
程序猿_极客3 天前
【免费】分享一套优质的基于SSM的校园失物招领系统的设计与实现,源码+文档+视频详解(讲解)
java·mysql·ssm·课程设计·失物招领系统
张洛闻Eren3 天前
k8s云原生【第十课】:水平 Pod 自动扩缩容
运维·数据库·云原生·kubernetes·github
于平安3 天前
MySQL-触发器
数据库·mysql