MongoDB数据库信号和Node.js Process.NextTick()

这可能是一个坏主意,也可能是一个数据库并发问题的解决scheme。

我们有一个被调用来更新mongologging的方法。 我们正在看到一些并发性问题 – 进程A读取logging,进程B读取logging,进程A做出mods并保存logging,进程做B mods并保存logging。 因为B在A之后读取,在A写入之前,它不知道A所做的更改,而我们从A中丢失数据。

我想知道是否我们不能使用数据库信号量,基本上是集合上的一个字段,这是一个布尔值。 如果我们在方法开始时读取logging,并且该字段是正确的,那么正在编辑它。 此时,使用process.nexttick()重新调用该方法,使用相同的数据。 否则,设置信号量,并继续。

阅读和保存之间还有一段时间,但是它应该比我们现在正在做的更快。

是这样的 任何想法,任何人都做了这样的事情? 它会甚至工作吗?

function remove_source(service_id,session, next) { var User = Mongoose.model("User"); /* get the user, based on the session user id */ User.findById(session.me,function(err,user_info) { if (user_info.semaphore === true) { process.nextTick(remove_source(service_id,session,next)); } else { user_info.semaphore = true; user_info.save(function(err,user_new) { if (err) next(err,user_new); else continue_on(null,user_new); }); } function continue_on(user_new) { etc....... } 

编辑:新代码:

该function现在看起来如下所示。 我正在做个别的更新arrays。 这当然意味着,如果第一次和第二次事务之间的事务失败,我现在有可能使数据不同步。 我在想,我可以简单地重新保存我进入函数时检索到的用户对象,覆盖我的更改。 我不知道如果我没有改变这个对象,mongoose/蒙戈是不会做这个保存的,只好试试看。 还有什么想法?

  var User = Mongoose.model("User"); /* get the user, based on the session user id */ User.findById(session.me,function(err,user_info) { if (err) { next(err,user_info,null); return; } if (!user_info || user_info.length === 0) { next(_e("ACCOUNT_NOT_FOUND"),"user_id: " + session.me); return; } var source_service_info = _.where(user_info.credentials, {"source_service_id": service_id}); var source_service = source_service_info.source_service; User.findByIdAndUpdate(session.me,{$pull: {"credentials": {"source_service_id": service_id}}},{},function(err,user_credential_removed) { if (err) { next(err,user_info,null); return; } User.findByIdAndUpdate(session.me,{$pull: {"criteria": {"source_service": source_service}}},{},function(err,user_criteria_removed) { if (err) { next(err,user_info,null); return; } else { next(null,user_criteria_removed); } }); }); }); 

};

你的方法的问题是它只是缩短了数据可以被第二个进程读取的时间,它并没有消除这个问题。

解决这个问题的方法是将信号设置为与读取操作相同的操作。 我没有使用Mongoose,但在MongoDB中,如果信号量为false,则可以使用findAndModify返回用户logging;如果为false,则在一个primefaces操作中,将信号量设置为true。

如果你不想使用findAndModify,只有在没有设置信号量的情况下,你才可以首先做一个更新来设置信号是真的(或者是某个特定的ID值,所以你知道它是你的信号量)。 然后,如果这个过程成功,你可以做的发现(也许传递你的信号量ID作为标准在发现)。 但是,findAndModify(如果它在Mongoose中可用)将一步完成此操作。

在这里描述了一个变化: http : //docs.mongodb.org/manual/tutorial/isolate-sequence-of-operations/在那里你做一个乐观locking的forms,检查旧的值保持不变,然后将其更改为新的价值观。

有一个变化,使用一个单独的表模拟两阶段提交: http : //docs.mongodb.org/manual/tutorial/perform-two-phase-commits/

编辑:在下面的交stream,这似乎是一个架构和更新问题。 问题可能会变成这样:我在数组中有一些条目,这些条目的序号索引也与其他数组相关。 如何执行删除而不会有不匹配?

根据现实世界中的频率与QAtesting情况,可能出现三种可能性。

  1. 考虑添加一个已删除的标志,但保持logging在相同的顺序。 如果有人切换,重复使用相同的logging,但无论您想要如何修复。
  2. 对每个元素使用一个关联数组(JS对象)(而不是来自关系世界的特征)。如果您需要一个订单,请添加一个按顺序列出键的数组。 两者都有语法更新,而不涉及其他任何已经改变的内容,并且不会覆盖对不同领域的改变。
  3. 使用键是数字的关联数组。 实际删除不会影响检索。

    stuff = {} stuff [1] = {some:'details'} stuff [2] = {some:'details2'}

是1)你是否在同一领域做出改变? 把它变成一个数组,并推送更改,并popup最新的读取当前值。

2)你是否在改变不同的领域,但数据正在遭受挫折? 然后有更好的语法用于更新。 您可以逐个字段进行更新。

 $set: { 'fielda': 'valuea' } 

不会丢失以前的字段的编辑

3)改变你的模式

4)改变进程的时间,使它们不重叠。 或者,他们这样做在较小的子集,你可以设法防止重叠。

我想知道,出于兴趣,需要多个进程来更新相同的logging? 我不用任何看起来像的东西。