处理 SQL 死锁(Deadlock)通常需要预防、检测、定位和优化相结合。下面从原理 → 排查 → 解决 → 预防四个层面系统说明。
死锁一般满足四个条件(缺一不可):
只要打破任意一个条件,就能避免死锁。
SHOW ENGINE INNODB STATUS;
重点关注:
LATEST DETECTED DEADLOCK开启死锁日志(推荐):
[mysqld]
innodb_print_all_deadlocks = 1
SELECT * FROM sys.dm_tran_locks;
或:
DBCC TRACEON(1222, -1);
SELECT * FROM v$lock WHERE block = 1;
事务A:更新表1 → 更新表2
事务B:更新表2 → 更新表1
✅ 解决方案
所有事务都:先表1,再表2
没有索引 → 行锁变成表锁
✅ 解决方案
WHERE 条件加索引UPDATE ... WHERE 非索引字段事务太大、太慢 → 锁持有时间长
✅ 解决方案
SELECT ... FOR UPDATE
多个事务同时锁定不同行
✅ 解决方案
FOR UPDATE 范围for (int i = 0; i < 3; i++) {
try {
update();
break;
} catch (DeadlockException e) {
Thread.sleep(50);
}
}
死锁是“正常异常”,不是程序错误
❌ 错误:
@Transactional
public void bigMethod() {
updateA();
callRemoteApi(); // 网络耗时
updateB();
}
✅ 正确:
updateA();
callRemoteApi();
updateB(); // 各自事务
RR(可重复读)→ RC(读已提交)innodb_lock_wait_timeout = 5
(死锁等待时间,避免雪崩)
死锁不可怕,可怕的是“顺序乱 + 事务长 + 没索引 + 不重试”
如果你愿意,可以:
我可以直接帮你分析死锁根因并给优化方案。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。