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

实现关系型数据库乐观锁:何时何地检查行版本?

关系型数据库乐观锁实现方案解析

针对你提出的乐观锁实现问题,直接给你明确结论和最优方案:

一、版本比较的正确位置

版本比较应该直接放在UPDATE语句的WHERE条件中,利用数据库的原子操作保证并发场景下的数据一致性,这是实现乐观锁的标准做法。

不需要在应用层先查询数据库当前版本再做比较——这种方式不仅冗余,还可能在两次查询的间隙被其他线程修改数据,导致判断失效。

二、你提出的事务方案是否合适?

不合适。你给出的方案存在两个明显问题:

  1. 多了一次不必要的数据库查询,增加性能开销;
  2. 两次查询之间存在时间窗口,其他线程可能在这个窗口内修改数据,导致你拿到的版本已经过时,判断逻辑失去意义。

三、正确的实现方式

步骤1:获取用户数据(包含版本号)

SELECT id, name, version FROM users WHERE id = 1;
const jhon = get_user_by_id('1');
jhon.change_name_to('Jhin');

步骤2:在save方法中执行带版本校验的UPDATE

直接在UPDATE语句的WHERE条件里同时匹配id和获取到的version,同时将版本号自增:

function save(user) {
  // 注意:实际代码要做SQL注入防护,此处为简化写法直接拼接
  const updateResult = query(`
    UPDATE users
    SET name = '${user.name}', version = ${user.version + 1}
    WHERE id = ${user.id} AND version = ${user.version};
  `);

  // 通过受影响行数判断更新是否成功
  if (updateResult.affectedRows === 0) {
    throw new Error("乐观锁冲突:该数据已被其他操作修改,请重试");
  }
}

原理说明

数据库的UPDATE操作是原子性的,执行这条语句时,数据库会同时检查id和version是否匹配:

  • 如果匹配,说明没有其他线程修改过这条数据,执行更新并把版本号+1;
  • 如果不匹配,说明数据已被修改,更新不会生效,受影响行数为0,此时在应用层抛出冲突异常即可。

如果业务需要多个操作原子执行,可以将UPDATE放在事务中,但核心逻辑依然是利用WHERE条件做版本校验,不需要额外查询版本号。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 20:36:23