首页 > 解决方案 > 如何防止两个 Node 进程同时运行时插入完全相同的数据库记录?

问题描述

我有一个 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 个 Lambdas 同时启动时,它们会进入竞争条件,例如,其中 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
    });
}

标签: javascriptnode.jspostgresqlaws-lambdaknex.js

解决方案


像这样的代码:

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

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

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


推荐阅读