防止Node.js中与数据库相关的争用情况

概观

我正在尝试了解如何在使用Node.js时使用模型实例来确保asynchronous安全。 在这里,我在代码示例中使用了Mongoose ODM,但这个问题适用于任何使用Node.js采用的asynchronous事件驱动的I / O方法的数据库。

考虑下面的代码(它使用Mongoose进行MongoDB查询):

片段A

MyModel.findOne( { _id : <id #1> }, function( err, doc ) { MyOtherModel.findOne( { _id : someOtherId }, ( function(err, otherDoc ) { if (doc.field1 === otherDoc.otherField) { doc.field2 = 0; // assign some new value to a field on the model } doc.save( function() { console.log( 'success' ); } }); }); 

在应用程序的单独部分,MyModel描述的文档可以被更新。 考虑下面的代码:

片段B

 MyModel.update( { _id : <id #1> }, { $set : { field1 : someValue }, callback ); 

在代码片段A中,一旦文档准备就绪,MongoDB查询就会发出一个已注册的callback。 由MyModel描述的文档实例保留在内存中(在“doc”对象中)。 以下顺序可能会发生:

  1. 代码片段A执行
  2. 为MyModel启动一个查询,注册一个callback(callbackA)供以后使用
  3. <<节点事件循环运行>>
  4. 从数据库中检索MyModel,执行已注册的callback(callback A)
  5. 为MyOtherModel启动一个查询,注册一个回叫供以后使用(callbackB)
  6. <<节点事件循环运行>>
  7. 代码段B执行
  8. 文档(id#1)已更新
  9. <<节点事件循环运行>>
  10. 从数据库中检索MyOtherModel,执行已注册的callback(callback B)
  11. 文档(id#1)的陈旧版本在比较中被错误地使用。

问题

  1. 有没有保证这种types的竞争条件不会发生在Node.js / MongoDB中?
  2. 我能做些什么来确定性地防止这种情况发生?

虽然Node以单线程的方式运行代码,但在我看来,任何允许运行的事件循环都会为潜在的陈旧数据打开大门。 如果这个观察是错误的,请纠正我。

不,不能保证在node.js / MongoDB中不会出现这种types的竞争条件。 不过,它与node.js没有任何关系,而且支持并发访问的任何数据库都是可能的,而不仅仅是MongoDB。

但是,使用MongoDB解决这个问题比较棘手,因为它不支持像典型的SQL数据库那样的事务。 所以你必须在你的应用程序层使用MongoDB食谱中列出的策略来解决这个问题 。