此代码会导致 Node.js 中的竞争条件吗?

Could this code cause race condition in Node.js?

我在 Sails.js (v0.12.13) 中工作,我在控制器中的一项操作如下所示:

create: function(req, res){

    var comment = req.body;

    var image_id = req.params.id;

    Image.findOne(image_id).populate('comments').exec(function(err, image){


        image.messages.add(comment);

        image.save(function(err){

            return res.created(comment);

        });
    });
}

(省略错误处理)

基本上这会将 comment 添加到 image。首先,我需要获取图像及其评论,将新评论添加到数组中,然后再次保存。

然而,我的直觉是,当两个不同的人尝试添加评论时,事件的顺序是:

  1. 请求 #1 执行 findOne() 并被阻止
  2. 请求 #2 执行 findOne() 并被阻止
  3. 请求 #1 添加评论,执行 save() 并被阻止
  4. 请求 #2 添加评论,执行 save() 并被阻止
  5. 两个请求都有相同的原始 findOne() 结果,并且他们添加了自己的评论,所以当他们保存它时,只剩下最后一个。

这种情况会发生在 Node.js 吗?,或者有什么东西可以阻止这种情况发生吗?

我在网站上看到了一些例子,比如 http://sailsjs.com/documentation/reference/waterline-orm/populated-values/add 他们做了类似的事情。如果竞争条件可能发生,那么 Sail.js 对我来说就无法使用了,因为我发现这些东西非常重要。

提前致谢。

您实际上是在问您的代码是否是线程安全的,在 Node.js 中它是默认的。参见 here or here

您的变量都在它们自己的函数中,因此也在它们自己的执行上下文或范围内,因此您不会更改任何全局(共享)变量。

docs 声明:

Query objects (aka query instances) are the chainable deferred objects returned from model methods like .find() and .create(). They represent a not-quite-yet-fulfilled intent to fetch or modify records from the database.

所以不,findOne() 不会阻止。这完全取决于特定数据库引擎的 exec() 方法。如果数据库驱动有非阻塞API,那么就不会有阻塞。竞争条件也将取决于底层的 DBMS 实现。但是 findOne 不会导致竞争条件。

简答:别担心,这样您不会丢失/覆盖数据。


Can this happen in Node.js?

is there something that prevents this from happening?


此条件不特定于Node.js或异步、基于事件循环的执行。
由于线程抢占,2 个线程处理其他语言(Java、Ruby 等)的 2 个请求可能会发生类似的事情。

有问题的实施

  1. 请求#1 获取图像并获取 { id: 1, comments: [1, 2] }
  2. 请求#2 获取图像并获取 { id: 1, comments: [1, 2] }
  3. Req#1 添加注释,因此对象变为 { id: 1, comments: [1, 2, 3] }。保存时,它确保只有 1、2、3 条评论与图像 1 相关联。
  4. Req#2 添加注释,使对象变为 { id: 1, comments: [1, 2, 4] }。保存时,它确保只有 1、2、4 条评论与图像 1 关联,从而 删除 评论 3

实际实施

  1. 同上1
  2. 同上2
  3. Req#1 添加注释以便添加查询对象记录 Comment#3。类似于 { id: 1, comments: { value: [1, 2], addModels: [3] }。保存时,在数据库中 Comment#3Image#1 之间创建关联。
  4. Req#2 添加注释以便添加查询对象记录 Comment#4。类似于 { id: 1, comments: { value: [1, 2], addModels: [4] }。保存时,会在数据库中的 Comment#4Image#1 之间创建关联。较早创建的关联是 Comment#3 未触及

相关代码:

  1. 吃水线association.js
  2. 吃水线save.js