此代码会导致 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 执行 findOne() 并被阻止
- 请求 #2 执行 findOne() 并被阻止
- 请求 #1 添加评论,执行 save() 并被阻止
- 请求 #2 添加评论,执行 save() 并被阻止
- 两个请求都有相同的原始 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 获取图像并获取
{ id: 1, comments: [1, 2] }
- 请求#2 获取图像并获取
{ id: 1, comments: [1, 2] }
- Req#1 添加注释,因此对象变为
{ id: 1, comments: [1, 2, 3] }
。保存时,它确保只有 1、2、3 条评论与图像 1 相关联。
- Req#2 添加注释,使对象变为
{ id: 1, comments: [1, 2, 4] }
。保存时,它确保只有 1、2、4 条评论与图像 1 关联,从而 删除 评论 3
实际实施
- 同上1
- 同上2
- Req#1 添加注释以便添加查询对象记录
Comment#3
。类似于 { id: 1, comments: { value: [1, 2], addModels: [3] }
。保存时,在数据库中 Comment#3
和 Image#1
之间创建关联。
- Req#2 添加注释以便添加查询对象记录
Comment#4
。类似于 { id: 1, comments: { value: [1, 2], addModels: [4] }
。保存时,会在数据库中的 Comment#4
和 Image#1
之间创建关联。较早创建的关联是 Comment#3
未触及。
相关代码:
- 吃水线association.js
- 吃水线save.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 执行 findOne() 并被阻止
- 请求 #2 执行 findOne() 并被阻止
- 请求 #1 添加评论,执行 save() 并被阻止
- 请求 #2 添加评论,执行 save() 并被阻止
- 两个请求都有相同的原始 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 获取图像并获取
{ id: 1, comments: [1, 2] }
- 请求#2 获取图像并获取
{ id: 1, comments: [1, 2] }
- Req#1 添加注释,因此对象变为
{ id: 1, comments: [1, 2, 3] }
。保存时,它确保只有 1、2、3 条评论与图像 1 相关联。 - Req#2 添加注释,使对象变为
{ id: 1, comments: [1, 2, 4] }
。保存时,它确保只有 1、2、4 条评论与图像 1 关联,从而 删除 评论 3
实际实施
- 同上1
- 同上2
- Req#1 添加注释以便添加查询对象记录
Comment#3
。类似于{ id: 1, comments: { value: [1, 2], addModels: [3] }
。保存时,在数据库中Comment#3
和Image#1
之间创建关联。 - Req#2 添加注释以便添加查询对象记录
Comment#4
。类似于{ id: 1, comments: { value: [1, 2], addModels: [4] }
。保存时,会在数据库中的Comment#4
和Image#1
之间创建关联。较早创建的关联是Comment#3
未触及。
相关代码:
- 吃水线association.js
- 吃水线save.js