数据库死锁(Deadlock)是指两个或多个事务在执行过程中,因互相持有对方需要的锁而互相等待,导致都无法继续前进的情况。
下面从常见操作 / 场景来说明什么操作容易引发死锁。
最常见死锁原因
事务A:
UPDATE table1 SET ... WHERE id = 1;
UPDATE table2 SET ... WHERE id = 2;
事务B:
UPDATE table2 SET ... WHERE id = 2;
UPDATE table1 SET ... WHERE id = 1;
✅ 本质:加锁顺序不一致
事务A:
UPDATE user SET money = money - 10 WHERE id = 1;
UPDATE user SET money = money + 10 WHERE id = 2;
事务B:
UPDATE user SET money = money - 10 WHERE id = 2;
UPDATE user SET money = money + 10 WHERE id = 1;
即使是一张表,也会死锁。
-- 事务A
SELECT * FROM order WHERE id = 1 FOR UPDATE;
UPDATE order SET status = 2 WHERE id = 2;
-- 事务B
SELECT * FROM order WHERE id = 2 FOR UPDATE;
UPDATE order SET status = 2 WHERE id = 1;
FOR UPDATE 会加行锁,顺序反了就死锁。
-- 事务A
UPDATE user SET age = 18 WHERE id BETWEEN 1 AND 10;
-- 事务B
INSERT INTO user(id, name) VALUES (5, 'Tom');
更新主表 → 子表自动加锁
另一个事务反向更新 → 死锁
外键检查会隐式加锁,容易被忽略。
| 场景 | 是否常见 |
|---|---|
| 更新顺序不一致 | ✅ 最常见 |
| 并发修改多行 | ✅ |
| 显式 FOR UPDATE | ✅ |
| 间隙锁 / 范围锁 | ✅(MySQL) |
| 外键级联 | ⚠️ |
| 单条 UPDATE | ❌ 几乎不会 |
✅ 1. 统一加锁顺序
永远先锁 id=1,再锁 id=2
✅ 2. 缩小事务范围
✅ 3. 避免 SELECT FOR UPDATE 滥用
✅ 4. 使用索引,避免表锁
✅ 5. 设置死锁重试机制
捕获 Deadlock 异常 → 重试事务
死锁不是“某个操作”的问题,而是“多个事务以不同顺序抢同一批锁”的问题。
如果你愿意,我可以:
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。