javascript - 如何防止两个 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
});
}
解决方案
像这样的代码:
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 创建记录. 然后,它将自动创建或返回错误,并且没有机会出现竞争条件。您只需查找错误并处理它
推荐阅读
- json - 如何使用 jq 中的流选项从 JSON 文件中检索键和值
- c++ - C++ WinAPI - GetConsoleScreenBufferInfo 总是因句柄无效而失败(返回 0)
- spring - 我想使用 Spring Boot 和 JPA 存储 JSON
- javascript - 如何从主页的闪屏播放视频?
- scala - Scala 中 SimpleCurveFitter 上的 ConvergenceException
- cmake - 如何在 CMAKE 中将标志传递给 nvcc 编译器
- php - 用mysql在php中进行分页
- javascript - Drupal 7:使用 drupal_add_js 时如何将 async 属性添加到外部 JS 脚本?
- node.js - 保存/创建时存在猫鼬检查值并通过响应发送
- java - 为什么我总是在 android 3.1.2 中出现 R 错误?