innodb如何检测死锁_mysql死锁机制说明

11次阅读

InnoDB通过等待图算法主动检测死锁,构建事务节点与等待边的有向图,DFS遍历找环;死锁发生后按持有锁数少、undo log小选牺牲者回滚,并报错1213;依赖innodb_deadlock_detect(默认ON)和innodb_lock_wait_timeout(默认50秒)协同控制,可通过SHOW ENGINE INNODB STATUS查看最近死锁详情。

innodb如何检测死锁_mysql死锁机制说明

InnoDB 检测死锁主要依靠等待图(Wait-for Graph)算法,这是一种主动式、实时的检测机制,不是靠超时被动发现。当事务申请锁但无法立即获得时,InnoDB 就会把这个等待关系加入等待图中,并检查是否存在环形依赖——只要发现环,就判定为死锁。

等待图是怎么构建和检测的

每个事务是一个节点,如果事务 A 正在等待事务 B 释放某把锁,就在图中画一条从 A 指向 B 的有向边。InnoDB 在每次加锁阻塞时都会触发一次图遍历,深度优先搜索是否存在闭环。一旦发现闭环(比如 A→B→C→A),说明这三个事务形成了循环等待,满足死锁四条件中的“循环等待”,立刻启动处理流程。

死锁发生后自动选哪个事务回滚

InnoDB 不随机选择,而是评估每个参与事务的“代价”:

  • 有锁的数量越少,越可能被选为牺牲者
  • 事务已执行的语句越少、undo log 越小,回滚开销越低
  • 默认不考虑事务优先级或提交顺序,只看资源占用成本

回滚后,该事务收到错误码 1213 (ER_LOCK_DEADLOCK),其余事务可继续执行。

两个关键参数控制行为

innodb_deadlock_detect:默认开启(ON),决定是否启用等待图检测。关闭后仅依赖超时机制,容易造成长时间阻塞,不推荐生产环境关闭。

innodb_lock_wait_timeout:默认 50 秒,是兜底策略。即使没触发死锁检测,等待锁超过这个时间也会报错退出,防止无限挂起。

怎么确认刚发生的死锁

执行 SHOW ENGINE INNODB STATUSG,重点关注输出末尾的 LATEST DETECTED DEADLOCK 区域。里面会列出:

  • 两个(或多个)冲突事务的完整 sql 语句
  • 各自持有的锁类型(record lock / gap lock / next-key lock)和行位置
  • 谁在等谁、等待哪条记录、锁模式(X/S)
  • 被回滚的是哪一个事务及其 ID

这是定位死锁根因最直接的一手信息。

text=ZqhQzanResources