sql - 如何使用 MAX()+1 获得快速 SQL 插入以始终在每次调用之间递增?
问题描述
我有一个 REST-ish 端点,它创建一个day
对象并将其order
属性设置为maximum order is +1
. 我遇到一个问题,即快速连续调用该端点会导致某些端点days
具有相同的order
. 我该如何解决这个问题?
SQL Query 就是这样。
insert into "days" ("order", "program_id") values (
(select max(days.order)+1
from "days"
where "days"."program_id" = '5'), '5')
returning *
它会导致类似
{"program_id":5,"id":147,"order":38}
{"program_id":5,"id":150,"order":38}
{"program_id":5,"id":148,"order":38}
{"program_id":5,"id":149,"order":38}
{"program_id":5,"id":151,"order":39}
{"program_id":5,"id":152,"order":40}
{"program_id":5,"id":153,"order":41}
如果有帮助,我在 Node (Express) 上并使用 Knex 和 Objection 为 Postgres 数据库构建查询。JavaScript 代码如下。
json.order = knex.select(knex.raw('max(days.order)+1'))
.from('days')
.where('days.program_id', json.program_id);
return await Days
.query(trx)
.returning('*')
.insert(json);
我也在使用max+1
,因为我希望订单值逐个递增program
。所以days
aprogram
会有唯一性orders
,但也有可能days
不同programs
与相同order
。
谢谢!
解决方案
您可能会select ... for update
在您正在计算的子查询中添加锁定max+1
:
json.order = knex.select(knex.raw('max(days.order)+1'))
.forUpdate() // <-------- lock rows
.from('days')
.where('days.program_id', json.program_id);
因此,在此事务结束之前,没有其他并发连接可以读取用于计算最大值的那些行。