温馨提示×

温馨提示×

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

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

怎样处理SQL死锁问题

发布时间:2026-10-07 07:34:31 来源:亿速云 阅读:103 作者:小樊 栏目:数据库

处理 SQL 死锁(Deadlock)通常需要预防、检测、定位和优化相结合。下面从原理 → 排查 → 解决 → 预防四个层面系统说明。


一、理解死锁产生的本质

死锁一般满足四个条件(缺一不可):

  1. 互斥:资源只能被一个事务占用
  2. 持有并等待:事务持有资源并等待其他资源
  3. 不可剥夺:资源不能被强制释放
  4. 循环等待:A 等 B,B 等 A

只要打破任意一个条件,就能避免死锁。


二、快速定位死锁(非常关键)

1️⃣ MySQL

SHOW ENGINE INNODB STATUS;

重点关注:

  • LATEST DETECTED DEADLOCK
  • 涉及的事务、SQL、锁类型(S / X)

开启死锁日志(推荐):

[mysqld]
innodb_print_all_deadlocks = 1

2️⃣ SQL Server

SELECT * FROM sys.dm_tran_locks;

或:

DBCC TRACEON(1222, -1);

3️⃣ Oracle

SELECT * FROM v$lock WHERE block = 1;

三、常见死锁场景 & 解决方案

✅ 场景 1:更新顺序不一致(最常见)

事务A:更新表1 → 更新表2
事务B:更新表2 → 更新表1

✅ 解决方案

  • 统一访问顺序
所有事务都:先表1,再表2

✅ 场景 2:索引缺失导致锁升级

没有索引 → 行锁变成表锁

✅ 解决方案

  • 为 WHERE 条件加索引
  • 避免 UPDATE ... WHERE 非索引字段

✅ 场景 3:长事务

事务太大、太慢 → 锁持有时间长

✅ 解决方案

  • 拆分大事务
  • 减少事务中无关操作
  • 避免事务中调用接口 / 睡眠

✅ 场景 4:SELECT + UPDATE 混合

SELECT ... FOR UPDATE

多个事务同时锁定不同行

✅ 解决方案

  • 明确锁定顺序
  • 尽量使用索引
  • 减少 FOR UPDATE 范围

四、代码层面的处理策略

✅ 1. 捕获死锁并重试(强烈推荐)

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

死锁是“正常异常”,不是程序错误


✅ 2. 控制事务粒度

❌ 错误:

@Transactional
public void bigMethod() {
    updateA();
    callRemoteApi(); // 网络耗时
    updateB();
}

✅ 正确:

updateA();
callRemoteApi();
updateB(); // 各自事务

✅ 3. 降低隔离级别(视业务)

  • RR(可重复读)→ RC(读已提交)
  • 减少 GAP 锁

五、数据库参数优化(辅助)

MySQL

innodb_lock_wait_timeout = 5

(死锁等待时间,避免雪崩)


六、死锁预防 checklist ✅

  • [ ] 所有事务访问表顺序一致
  • [ ] WHERE 条件有索引
  • [ ] 事务尽可能短
  • [ ] 避免大事务
  • [ ] 捕获并重试死锁
  • [ ] 开启死锁日志

七、一句话总结

死锁不可怕,可怕的是“顺序乱 + 事务长 + 没索引 + 不重试”

如果你愿意,可以:

  • 发 具体 SQL / 表结构
  • 或说明 数据库类型(MySQL / PG / SQL Server)

我可以直接帮你分析死锁根因并给优化方案。

向AI问一下细节

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

AI
助
手