当同时运行时,如何防止两个Node进程插入完全相同的数据库记录?

时间:2019-04-19 05:43:00

标签: javascript node.js postgresql aws-lambda knex.js

我有一个Lambda,可以一次发送数千个事件。并发保留为默认值,这意味着AWS将启动多个实例来处理传入事件。 Lambda会获取数据并将一些数据插入数据库(如果该数据尚不存在)。 Lambda用Node.js编写,并使用Knex连接到Postgres数据库。

Lambda本质上包含以下逻辑:

Does a record with ID X exist?     
a. Yes: do nothing
b. No: create a new record with ID X.

问题在于,当同时旋转50个Lambda时,它们将进入竞争状态,例如其中3或4个将同时(或彼此之间以毫秒为单位)检查现有记录)并找不到它,因此会插入多个重复的记录。

我知道解决此问题的一种方法是在表上创建唯一约束,以防止ID为X的多个记录。然后我的逻辑将如下所示:

Does a record with ID X exist? 
a. Yes: do nothing 
b. No: create a new record with ID X.
   b.1. Did that succeed?
      a. Yes: continue on.
      b. No, it threw a unique constraint error: go back to line 1.

这似乎有些人为的,但应该可以。有更好的选择吗?

编辑:

这是实际代码:

let location = await Location.query().where({ external_id }).first();
if(!location){
    location = await Location.query().insert({
        name,
        external_id
    });
}

1 个答案:

答案 0 :(得分:2)

这样的代码:

Does a record with ID X exist?      
a. Yes: do nothing 
b. No: create a new record with ID X.

不以某种方式锁定数据库是一种竞争条件。在查询记录X和创建记录X之间,其他一些请求也可以创建它。永远不要这样做。这是情欲。

您必须查看数据库提供的特定工具,但是执行上述序列的一种常见方法是设置数据库,以使其不允许ID X重复,然后您尝试创建记录ID为x。然后,它将自动创建或返回错误,并且没有机会出现竞争状况。您只需查找错误并加以处理