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

悲观锁如何防止更新丢失?基于Ask TOM的场景探讨

关于悲观锁场景下预防更新丢失的问题

首先明确:你描述的场景确实属于更新丢失——会话2基于提交前的旧数据生成更新语句,在获取锁后直接覆盖了会话1的变更,完全符合Ask TOM对更新丢失的定义:未感知到他人的变更就覆盖更新。

在悲观锁场景下,可以通过以下两种核心方式预防这类问题:

1. 遵循「先锁后读再更新」的完整流程

不要直接执行更新语句,而是先通过SELECT ... FOR UPDATE锁定目标行,再基于锁定后读取到的最新数据构造更新语句:

  • 会话1执行:SELECT address, phone FROM emp WHERE empno = 10 FOR UPDATE,锁定该行并读取当前数据
  • 会话1基于读取到的数据修改后,执行:UPDATE emp SET address = 'London', phone = 123 WHERE empno = 10,随后提交
  • 会话2执行SELECT ... FOR UPDATE时会被阻塞,直到会话1提交;此时会话2读取到的是会话1更新后的最新数据,再构造的更新语句就不会覆盖之前的变更

这种方式确保了所有更新操作都是基于锁定后的最新数据执行,从根源上避免了基于旧数据的覆盖更新。

2. 在更新语句中加入原始读取的字段条件(悲观锁+条件校验)

即使直接执行更新,也可以在WHERE子句中带上读取到的原始字段值,让数据库帮你校验数据是否被修改:
比如会话2读取到的原始地址是'OldAddr'、电话是'OldPhone',更新语句写成:

UPDATE emp SET address = 'Brighton', phone = 456 
WHERE empno = 10 AND address = 'OldAddr' AND phone = 'OldPhone';

如果会话1已经修改了数据,这条语句会返回0行受影响,应用层可以捕获这个结果,提示用户「数据已被其他用户修改,请重新刷新后操作」。

这种方式相当于在悲观锁的基础上叠加了校验逻辑,既利用了悲观锁的阻塞特性,又避免了无意识的覆盖更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 17:48:08