同时保存同一文档将覆盖另一个文档

时间:2014-10-11 11:05:23

标签: mongodb concurrency

同时保存同一文档只会保存一次。

我在我的应用中有这个流程:

doc.money = 0

  • 获取doc(流程1)
  • 获取doc(流程2)
  • 更改doc.money + = 5(流程1)
  • 更改doc.money + = 10(流程2)
  • 保存文档(流程1)
  • 保存文档(流程2)

现在我的doc.money等于10而不是15。

如何解决这个问题?甚至不会抛出错误..

使用inc:5更新无法在我的应用中使用,因为:

Logic.js(在客户端和服务器上共享):

var logic = function(doc, options){
    doc.a = options.x;
    // Some very complex logic here...
}

Server.js

// incoming ajax request
// query database and get a doc
logic(doc, options)
doc.save(...)

Client.js

// I have my doc
logic(doc, options);
// Now I have my logic applied

好处?

  • 我只写了一次我的应用程序的logic.js。
  • 忘记更新逻辑的某些部分没有错误。

经典方式

Server.js

// incoming ajax request
// query database and get a doc
// Some very complex logic here...
var update = {/*insert here the complex part*/}
Doc.update(cond, update, ...)

Client.js

// I have my doc
// Some very complex logic here...
// Now I have my logic applied

结论

正如您所看到的,在经典方式中,您只有两次逻辑,而且只有一次,更改反映了客户端和服务器端逻辑。

2 个答案:

答案 0 :(得分:3)

这实际上与2阶段提交无关,而是与版本控制无关。

您应用程序中的两个单独的线程正在向下发送同一文档的两个不同版本。

在任何数据库中修复此问题的最佳方法是使用版本控制:http://askasya.com/post/trackversions

答案 1 :(得分:1)

它被称为Race Condition。与典型的SQL数据库相比,在MongoDB中解决它很棘手。他们在cookbook上有一个解决方案(或者说是一个黑客)。

基本上,在文档中你有一个state键。对于每笔交易,您都要保留它的标签。例如,如果stateready,则可以对其执行操作。但首先你要将状态更改为pending。完成后,再次将其重新设置为ready。因此无论哪个进程首先进入它,都要更改状态,保存它,然后下一个进程就可以进行处理。您可以扩展这个想法,使其更加安全无虞。看看食谱链接。