You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用两条SQL UPDATE语句的问题:是否与排他锁相关?

两条UPDATE语句的锁问题分析与优化方案

嘿,你的疑问完全命中了关键点——两条独立的UPDATE语句确实大概率和排他锁(Exclusive Locks)脱不了干系,很容易引发性能瓶颈甚至死锁,我给你拆解下核心问题,再结合常见场景给出优化后的SQL:

为什么两条UPDATE会和排他锁有关?

当你执行第一条UPDATE时,数据库会对目标行加上排他锁,这个锁会一直持有到事务提交或回滚才释放。这里的问题分两种情况:

  • 如果两条UPDATE是分开执行(不在同一个事务内):第一条锁释放前,其他请求操作同表行时会被迫等待锁,直接拖慢系统吞吐量;
  • 如果两条UPDATE是放在同一个事务内:要是其他事务也反向操作相同的行(比如先更行B再更行A),就会触发经典的死锁——两个事务各自持有对方需要的锁,陷入无限等待。

假设原SQL是这类场景(模拟常见示例)

我先模拟一个你可能遇到的典型场景,比如转账操作里的两条更新:

-- 原两条UPDATE语句示例:从用户1转100到用户2
UPDATE users SET balance = balance - 100 WHERE id = 1;
UPDATE users SET balance = balance + 100 WHERE id = 2;

优化后的SQL方案

方案1:合并为单条UPDATE(优先推荐,适合同表操作)

如果操作的是同一张表,完全可以把两条语句合并成一条,这样只会对目标行加一次锁,事务提交后一次性释放,大幅降低锁冲突和死锁的概率:

UPDATE users 
SET balance = CASE 
    WHEN id = 1 THEN balance - 100 
    WHEN id = 2 THEN balance + 100 
    ELSE balance 
END 
WHERE id IN (1, 2);

方案2:显式事务+固定锁顺序(适合跨表或无法合并的场景)

如果必须分两条UPDATE执行,一定要把它们放在同一个显式事务里,并且固定更新顺序(比如始终先更新ID更小的行),从根源上避免交叉等待锁的死锁情况:

BEGIN TRANSACTION;
-- 固定更新顺序,先操作id=1,再操作id=2
UPDATE users SET balance = balance - 100 WHERE id = 1;
UPDATE users SET balance = balance + 100 WHERE id = 2;
COMMIT;

简单总结下:两条UPDATE的核心问题就是锁的持有时间延长、锁冲突概率飙升,在高并发场景下会直接导致系统卡顿甚至死锁。通过合并语句或者规范事务+锁顺序,就能有效解决这类问题啦。

内容的提问来源于stack exchange,提问作者SBT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:58:13