温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

数据库死锁怎么避免

发布时间:2026-10-27 06:10:42 来源:亿速云 阅读:105 作者:小樊 栏目:数据库

数据库死锁(Deadlock)是指两个或多个事务相互持有对方所需的锁,并互相等待对方释放,从而导致所有相关事务都无法继续执行的情况。

死锁无法 100% 彻底杜绝(尤其在高并发下),但可以通过设计、开发和运维手段大幅避免和减少。

下面从 设计原则、开发规范、数据库配置、运维监控 四个层面系统说明。


一、设计层面(最根本)

1. 统一访问顺序(最重要)

所有事务都按相同顺序访问表和行。

❌ 容易死锁:

  • 事务 A:先更新 user,再更新 order
  • 事务 B:先更新 order,再更新 user

✅ 避免方式:

  • 统一为:先 user,后 order

这是避免死锁最有效、最常用的方法。


2. 缩小事务范围

  • 事务越短,持锁时间越短
  • 不要在事务中:
    • 调用远程接口
    • 睡眠 / 等待用户输入
    • 做复杂计算

✅ 原则:事务只做数据库操作,尽快提交


3. 减少锁冲突

  • 避免大事务批量更新
  • 热点数据(如库存、余额)要特别设计
    • 行级锁优于表锁
    • 分段锁 / 队列处理

二、开发层面(实操规范)

4. 控制锁粒度

  • 尽量使用 行锁 而非表锁
  • 避免:
    SELECT * FROM table;
    UPDATE table SET ...;
    
    无索引的更新会导致锁全表

✅ 确保:

  • UPDATE / DELETE 有索引
  • WHERE 条件能命中索引

5. 避免长事务 + 高并发写

典型高危场景:

  • 先 SELECT,再 UPDATE
  • 多个事务同时更新同一行

✅ 推荐:

  • 使用 SELECT ... FOR UPDATE(明确加锁)
  • 或乐观锁(version 字段)
UPDATE account
SET balance = balance - 100, version = version + 1
WHERE id = 1 AND version = 2;

6. 合理设置事务隔离级别

隔离级别 死锁概率 说明
READ UNCOMMITTED 低 很少用
READ COMMITTED 中 推荐(Oracle 默认)
REPEATABLE READ 高 MySQL 默认,易锁等待
SERIALIZABLE 最高 性能差

✅ 多数系统:READ COMMITTED + 行锁


三、数据库层面(参数与机制)

7. 开启死锁检测 / 超时

  • MySQL:
    innodb_deadlock_detect = ON
    innodb_lock_wait_timeout = 5
    
  • 死锁发生时,数据库会:
    • 自动回滚代价小的事务
    • 抛出死锁异常

8. 使用合适索引

  • 没有索引 ⇒ 锁升级(行锁 → 表锁)
  • 联合索引顺序要与查询一致

四、运维与监控

9. 监控死锁

  • MySQL:
    SHOW ENGINE INNODB STATUS;
    
  • 错误日志:
    Deadlock found when trying to get lock
    

10. 应用层重试

死锁是可恢复错误:

捕获 Deadlock 异常 → 短暂退避 → 重试事务

✅ 通常重试 2–3 次即可


五、经典避免死锁 checklist ✅

  • [ ] 所有事务访问顺序一致
  • [ ] 事务尽可能短
  • [ ] UPDATE / DELETE 有索引
  • [ ] 避免表锁
  • [ ] 热点数据用乐观锁或队列
  • [ ] 设置锁等待超时
  • [ ] 应用捕获死锁并重试

如果你愿意,可以告诉我:

  • 使用的数据库(MySQL / PostgreSQL / Oracle)
  • 具体业务场景(订单 / 库存 / 账务)

我可以给你针对性的死锁避免方案或 SQL 示例。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI
助
手