You need to enable JavaScript to run this app. Postgres中SQL语句是否保证原子性?knex读写竞态如何解决?
优惠活动
大模型
产品
解决方案
定价
更多

Postgres中SQL语句是否保证原子性?knex读写竞态如何解决?

方案可行性与原子性说明

  • 你提到的将读写逻辑合并为单次数据库操作的方案,可以解决当前的竞态条件问题,核心规则如下:
    • PostgreSQL中单次执行的SQL语句、单次调用的PL/pgSQL函数默认具备原子性,整个读写逻辑要么全部执行成功,要么全部回滚,不会出现读完成、写未完成的中间状态对外暴露。
    • 并发场景下的读写可见性,取决于你具体的实现逻辑:
      • 如果使用UPDATE ... RETURNING语法实现(不需要额外编写PL/pgSQL,knex原生支持拼接),执行时会先对目标行加行级写锁,拿到锁后才会执行读、计算、写回的全流程,其他操作同一行的并发请求会被阻塞,直到前一个操作全流程完成、锁释放后才会执行,不会读到过期值。
      • 如果是在PL/pgSQL函数中先执行SELECT再执行UPDATE,需要在SELECT语句后加FOR UPDATE手动加行锁,才能达到和上面一致的效果;如果SELECT不加锁,即使逻辑封装在同一个PL/pgSQL函数中,仍有可能出现读取到旧值后、写回前其他请求已经修改了该行的问题,竞态依然存在。

适配knex的最优实现建议

无需编写PL/pgSQL即可实现原子的读改写操作,示例代码如下(以更新用户余额场景为例):

// 直接在数据库层完成「原值读取+计算+更新+返回新值」全流程
const updatedBalance = await knex('user_account')
  .update('balance', knex.raw('balance + ?', [10])) // 计算逻辑直接放在数据库侧执行
  .where('user_id', 123)
  .returning('balance') // 返回更新后的值
  .first();

该写法性能优于调用PL/pgSQL函数,且天然避免先读后写的竞态问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 11:36:07