数据库死锁预防策略 | AI生成和翻译

Home 2026.04

1. 数据库死锁是如何发生的

当两个(或多个)事务相互等待对方持有的锁形成循环时,就会发生死锁

典型示例:

此时:

形成死锁

MySQL(InnoDB)和 IBM Db2 都能检测到这种情况并终止其中一个事务以打破循环。


2. 死锁的实际成因(重要思维模型)

死锁不只是时间问题,还与以下因素相关:

关键因素:

因素 影响
不同的访问顺序 🚨 主要原因
事务持续时间长 增加发生概率
高并发 增加争用
范围锁 / 索引间隙锁 使情况更糟

3. 你的想法:”逐条执行SQL还是批量放入事务”

你可能在想:

多次小型SQL调用 → 反复加锁/解锁 → 更多争用 批量执行SQL → 总锁定时间更短 → 更好

这种想法部分正确但不完整

让我们分析两种情况:


情况A:逐条执行SQL(自动提交模式)

每条SQL:

优点:

缺点:


情况B:在事务中批量执行SQL

BEGIN;
UPDATE ...;
UPDATE ...;
COMMIT;

优点:

缺点:


4. 你的关键假设:”200ms vs 20ms 锁定时间”

这是你需要纠正的地方。

👉 死锁并不单纯与总锁定时间成正比

即使是20ms的事务也可能发生死锁,如果:

而一个200ms的事务可能不会死锁,如果:


5. 真正能减少死锁的方法(重要)

✅ 1. 一致的锁定顺序(最重要)

始终以相同的顺序访问行/表:

-- 总是先操作 id=1,再操作 id=2(绝不颠倒)

仅此一点就能消除大多数死锁。


✅ 2. 保持事务简短(但不要过度碎片化)


✅ 3. 适当的索引

如果缺少索引:

UPDATE table WHERE non_index_column = ...

→ 可能锁定多行甚至整个表


✅ 4. 避免不必要的锁


✅ 5. 重试逻辑

死锁在高并发系统中是正常的

MySQL和DB2都预期有这样的处理:

尝试:
    执行事务
捕获到死锁时:
    重试

6. 针对你问题的最终答案

将SQL语句批量放入事务中比逐条执行更好吗?

👉 答案:视情况而定,但通常是肯定的——有条件地肯定


7. 正确的思维模型(重要要点)

与其想:

“将总锁定时间从200ms减少到20ms”

不如想:

“确保所有事务以相同的顺序获取锁并尽快完成”

这才是真正防止死锁的方法。


8. 简单直观理解


如果你愿意,我可以展示真实的InnoDB死锁日志以及如何逐行分析它们——这是将理解变得非常具体的途径。


Back Donate