前置知识: MySQL

死锁检测与处理

00:00
1 min Advanced 2026/6/14

MySQL InnoDB死锁检测与处理:死锁检测算法、死锁日志分析、预防策略与自动恢复

1. 死锁检测

1.1 自动检测

InnoDB 自动检测,并回滚代价最小事务

-- 默认开启
SET GLOBAL innodb_deadlock_detect = ON;

-- 死锁发生时,被回滚的事务收到错误
-- ERROR 1213 (40001): Deadlock found when trying to get lock;
-- try restarting transaction

1.2 等图(Wait-for Graph)

InnoDB 使用等检测死锁:如果存在环,则存在

事务A 等待 事务B 持有的锁
事务B 等待 事务A 持有的锁
→ 形成环 → 死锁

2. 死锁日志

-- 查看最近一次死锁信息
SHOW ENGINE INNODB STATUS;

-- 死锁日志示例:
-- LATEST DETECTED DEADLOCK
-- ------------------------
-- 2026-06-14 10:30:00
-- *** (1) TRANSACTION:
-- TRANSACTION 12345, ACTIVE 2 sec starting index read
-- mysql tables in use 1, locked 1
-- LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
-- MySQL thread id 10, OS thread handle 12345, query id 100 localhost root updating
-- UPDATE accounts SET balance = balance - 100 WHERE id = 1
-- *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
-- RECORD LOCKS space id 58 page no 4 n bits 72 index PRIMARY of table `mydb`.`accounts`
-- *** (2) TRANSACTION:
-- TRANSACTION 12346, ACTIVE 1 sec starting index read
-- mysql tables in use 1, locked 1
-- 3 lock struct(s), heap size 1136, 2 row lock(s)
-- MySQL thread id 11, OS thread handle 12346, query id 101 localhost root updating
-- UPDATE accounts SET balance = balance - 100 WHERE id = 2
-- *** (2) HOLDS THE LOCK(S):
-- RECORD LOCKS ... index PRIMARY of table `mydb`.`accounts` trx id 12346 lock_mode X locks rec but not gap
-- *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
-- RECORD LOCKS ... index PRIMARY of table `mydb`.`accounts` trx id 12346 lock_mode X locks rec but not gap
-- *** WE ROLL BACK TRANSACTION (2)

3. 死锁预防

3.1 固定顺序访问

-- 所有事务按 id 升序访问
-- 事务A:先锁 id=1,再锁 id=2
-- 事务B:先锁 id=1,再锁 id=2
-- 不会形成环

3.2 缩短事务

-- 减少锁持有时间
BEGIN;
-- 只包含必要的操作
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

3.3 降低隔离级别

-- READ COMMITTED 比 REPEATABLE READ 锁范围更小
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

3.4 添加合适索引

-- 无索引时,InnoDB 锁定全表
-- 有索引时,只锁定匹配行
CREATE INDEX idx_accounts_id ON accounts(id);

4. 死锁恢复

-- 应用层重试
-- 捕获 1213 错误,自动重试
-- 建议重试3-5次

-- 设置锁等待超时
SET innodb_lock_wait_timeout = 5;  -- 5秒超时

-- 关闭死锁检测(高并发场景,降低检测开销)
SET GLOBAL innodb_deadlock_detect = OFF;
-- 此时依赖 innodb_lock_wait_timeout 超时回滚

知识检测

学习进度

-- 已学文档
--% 知识覆盖率

学习推荐

专注模式