首页 > 解决方案 > 如何使用 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。所以daysaprogram会有唯一性orders,但也有可能days不同programs与相同order

谢谢!

标签: sqlpostgresqlknex.jsobjection.js

解决方案


您可能会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);

因此,在此事务结束之前,没有其他并发连接可以读取用于计算最大值的那些行。


推荐阅读