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

SELECT FOR UPDATE 是否有必要?两种事务写法的差异探讨

两种事务写法的差异与SELECT FOR UPDATE的作用分析

核心差异

两种写法的本质区别在于加锁时机和适用场景:

第二种写法(直接UPDATE)

BEGIN;
UPDATE kv SET v = v + 5 WHERE k = 1;
COMMIT;

执行UPDATE语句时,数据库会先定位到k=1的行,立即为该行添加排他锁(X锁),完成更新后锁会一直持有到事务提交或回滚。整个过程锁的持有时间短,粒度精准。

第一种写法(SELECT FOR UPDATE + UPDATE)

BEGIN;
SELECT * FROM kv WHERE k = 1 FOR UPDATE;
UPDATE kv SET v = v + 5 WHERE k = 1;
COMMIT;

执行SELECT ... FOR UPDATE时,就会对k=1的行添加排他锁,后续的UPDATE因为已经持有锁,无需再次竞争锁资源。锁的持有时间从SELECT执行开始,到事务结束为止。

你的疑问解答

1. 第二种写法执行UPDATE前会锁定目标行吗?

是的。UPDATE的执行逻辑是:先找到匹配行并立即加排他锁,再执行更新操作,锁会持续到事务结束。不存在“读取后再锁定”的间隙,不会出现其他事务在这个过程中修改该行的情况。

2. 第一种写法是不是毫无用处?

当然不是,它的核心价值在于支持“先校验再更新”的业务逻辑:
当你需要先读取行数据做业务判断,再决定是否执行更新时,必须用SELECT FOR UPDATE锁定行,避免其他事务在“读取-判断-更新”的间隙修改数据,导致业务逻辑失效。

举个实际场景:实现“余额扣减”时,需要先确认余额大于0才能扣减:

BEGIN;
-- 锁定行并读取当前余额
SELECT v FROM kv WHERE k = 1 FOR UPDATE;
-- 业务判断后执行扣减(可在应用层或SQL的WHERE条件中实现判断)
UPDATE kv SET v = v - 5 WHERE k = 1 AND v > 0;
COMMIT;

如果不用SELECT FOR UPDATE,在SELECT和UPDATE之间,其他事务可能已经把余额改成0,导致扣减逻辑出错。

不过要注意:使用SELECT FOR UPDATE时,要尽量缩短锁的持有时间,不要在SELECT之后做耗时操作(比如调用第三方接口、等待用户输入),否则会导致锁长时间占用,引发其他事务的锁等待。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 06:20:06