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

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 STATUS\G,重点关注输出末尾的 LATEST DETECTED DEADLOCK 区域。里面会列出:
- 两个(或多个)冲突事务的完整 SQL 语句
- 各自持有的锁类型(record lock / gap lock / next-key lock)和行位置
- 谁在等谁、等待哪条记录、锁模式(X/S)
- 被回滚的是哪一个事务及其 ID
这是定位死锁根因最直接的一手信息。










