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

时间:2017-04-14 02:00:46

标签: javascript node.js sails.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()结果,并且他们添加了自己的注释,因此当他们保存时,只剩下最后一个。
  6. 这可以在Node.js中发生吗?,还是有什么可以防止这种情况发生?

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

    提前致谢。

3 个答案:

答案 0 :(得分:2)

简短回答:不用担心,您不会以这种方式丢失/覆盖数据。

  

这可以在Node.js中发生吗?

  

有什么可以防止这种情况发生吗?

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

有问题的实施

  1. Req#1获取图片并获取{ id: 1, comments: [1, 2] }
  2. Req#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
  5. 实际实施

    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 未触及
    5. 相关代码:

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

答案 1 :(得分:0)

docs表示:

  

查询对象(又称查询实例)是可链接的延迟对象   从.find()和.create()等模型方法返回。他们代表   一个尚未完成的意图来获取或修改记录   数据库中。

所以不,findOne()不会阻止。这一切都取决于特定数据库引擎的exec()方法。如果数据库驱动程序具有非阻塞API,则不会阻塞。竞争条件还取决于底层DBMS实现。但是findOne不会导致竞争条件。

答案 2 :(得分:-1)

你真的在问你的代码是否是线程安全的,在Node.js中它是默认的。请参阅herehere

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