温馨提示×

温馨提示×

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

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

关系数据库怎么避免死锁

发布时间:2026-09-03 21:38:13 来源:亿速云 阅读:92 作者:小樊 栏目:数据库

关系型数据库(如 MySQL、PostgreSQL、Oracle 等)中,死锁(Deadlock)通常出现在多个事务并发访问相同资源并以不同顺序加锁时。虽然不能完全杜绝死锁,但可以通过设计和运维手段大幅降低发生概率,或在发生时快速检测与恢复

下面从 设计、开发、数据库配置、运维 四个层面系统说明。


一、核心原则(最重要)

✅ 1. 统一加锁顺序

死锁最常见原因:加锁顺序不一致

❌ 错误示例:

  • 事务 A:先锁 表1 → 表2
  • 事务 B:先锁 表2 → 表1

✅ 正确做法:

  • 所有事务都按 固定顺序(如按主键、表名字典序)加锁
统一规则:
先锁 users,再锁 orders

二、开发层面的避免方法

✅ 2. 缩短事务长度

事务越长:

  • 持锁时间越久
  • 冲突概率越高

建议:

  • 事务中 只做必要操作
  • 避免在事务中:
    • 调用外部接口
    • sleep
    • 复杂计算
-- 不推荐
BEGIN;
UPDATE ...
CALL external_api();
COMMIT;

✅ 3. 尽早获取所需锁

不要“用到才锁”,而是事务开始就锁定所有资源

-- 推荐
BEGIN;
SELECT * FROM account WHERE id=1 FOR UPDATE;
SELECT * FROM account WHERE id=2 FOR UPDATE;
-- 业务逻辑
COMMIT;

✅ 4. 降低锁粒度

优先使用:

  • 行锁(Row Lock)
  • 避免表锁 ❌
操作 锁类型
UPDATE WHERE PK= 行锁
UPDATE 无索引 表锁
LOCK TABLE 表锁

确保 UPDATE / DELETE 使用索引

-- 有索引 → 行锁
UPDATE user SET money=money-10 WHERE id=1;

✅ 5. 避免锁升级

某些数据库在以下情况会从行锁升级为表锁:

  • 锁住大量行
  • 无合适索引

✅ 控制批量操作规模:

-- 分批
UPDATE orders SET status=1 WHERE id BETWEEN 1 AND 1000;

三、数据库层面的机制

✅ 6. 死锁自动检测(数据库已支持)

主流数据库都有死锁检测:

数据库 机制
MySQL (InnoDB) 自动检测并回滚代价小的事务
PostgreSQL 死锁超时(deadlock_timeout
Oracle 自动检测

不要试图“手动解决”,而是让数据库回滚


✅ 7. 设置合理的超时时间

避免事务无限等待:

MySQL:

SET innodb_lock_wait_timeout = 5;

PostgreSQL:

deadlock_timeout = 1s

四、应用层面的容错设计

✅ 8. 捕获死锁并重试(非常关键)

死锁是正常并发现象,应用必须能处理:

for (int i = 0; i < 3; i++) {
    try {
        executeTransaction();
        break;
    } catch (DeadlockException e) {
        Thread.sleep(50);
    }
}

✅ 重试是解决死锁的最后防线


五、隔离级别与死锁

✅ 9. 合理选择事务隔离级别

隔离级别 死锁风险
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE 最高

✅ 一般用:

  • MySQL:REPEATABLE READ(默认)
  • 高并发:READ COMMITTED

六、总结口诀(记住这几句)

统一顺序锁资源
事务尽量短而小
索引必须走行锁
死锁靠重试兜底


如果你愿意,我可以:

  • 具体 SQL 示例演示死锁产生过程
  • 针对 MySQL / PostgreSQL / Oracle 给专门建议
  • 帮你 审查现有事务代码是否易死锁

只要告诉我你用的数据库和场景即可。

向AI问一下细节

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

AI