这个代码可能会导致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); }); }); } 

(error handling被忽略)

基本上,这增加了对imagecomment 。 首先,我需要获取图像,并将其注释添加到数组中,然后再次保存。

然而,我的直觉是,有两种不同的人试图添加评论,事件的顺序是:

  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?

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


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

有问题的实施

  1. 需求#1获取图像并得到{ id: 1, comments: [1, 2] }
  2. 需求#2获取图像并得到{ id: 1, comments: [1, 2] }
  3. 需求#1增加了一个评论,所以对象变成{ id: 1, comments: [1, 2, 3] } 。 在保存时,它确保只有1,2,3个注释与图像1相关联。
  4. 需求#2增加了一个评论,所以对象变成{ id: 1, comments: [1, 2, 4] } 。 在保存时,它确保只有1,2,4个注释与图像1相关联,从而移除注释3

实际执行

  1. 和上面的1一样
  2. 和上面的2一样
  3. 需求#1添加评论,以便查询对象logging添加Comment#3 。 就像{ id: 1, comments: { value: [1, 2], addModels: [3] } 。 在保存时,在数据库中的Comment#3Image#1之间创build关联。
  4. 请求#2添加注释,以便添加查询对象loggingComment#4 。 类似于{ id: 1, comments: { value: [1, 2], addModels: [4] } 。 在保存时,在数据库中的Comment#4Image#1之间创build关联。 之前创build的关联是Comment#3 没有被触及

相关代码:

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

该文件指出:

查询对象(即查询实例)是从模型方法(如.find()和.create())返回的可链接延迟对象。 它们代表了从数据库中获取或修改logging的不完全意图。

所以不, findOne()不会阻塞。 这一切都依赖于特定数据库引擎的exec()方法。 如果数据库驱动程序具有非阻塞API,则不会有阻塞。 竞争条件也将取决于底层DBMS的实施。 但是findOne不会造成竞争状态。

你真的在问,如果你的代码是线程安全的,在Node.js中是默认的。 看到这里或这里 。

你的variables都在它们自己的函数中,因此也在它们自己的执行上下文或作用域中,所以你不会改变任何全局(共享)variables。