Mongoose 异步多次保存冲突
Posted
技术标签:
【中文标题】Mongoose 异步多次保存冲突【英文标题】:Mongoose asynchronous multiple save conflicts 【发布时间】:2014-10-24 01:46:01 【问题描述】:我在使用 Node/Mongoose/Socket.io 时遇到了一个很大的逻辑问题......假设我有一个服务器模型,它经常在我的应用程序中同时被调用,一些调用涉及更新模型中的数据。
db.Server.findOne(_id: reference.server).exec(function(error, server)
catches.error(error);
if (server !== null)
server.anything = "ahah";
server.save(function(error) );
有时,两个人会同时调用它,而第一个人会 save() 另一个人可能已经有 findOne 的“服务器”并得到了不是最新的“旧对象”并保存()它。
这里的大问题是,当第二个人保存()“服务器”(“旧对象”)时,它实际上会覆盖第一个的更改......你可以想象它会产生的大冲突我的申请。
我曾考虑将所有 save() 方法更改为 update() 以解决问题,但在项目中的某些时候,直接使用 update() 非常棘手,而且不实用。
有没有办法在有人更新 findOne() 调用时“锁定”它?就像当你 findOne() 时你也会说“嘿,我很快就会更新,所以不要让人们现在找到它”(使用 Mongoose,甚至是 MongoDb)
我找了好久没找到答案:(
希望你能理解我的问题;)谢谢!
【问题讨论】:
不。见***.com/questions/11076272/… 那么如何使用 mongo 建立一个有人员的网站? ... 您可以构建架构,以便您可以使用原子update
调用来完成所有文档修改。
Tricky ...如果他们无法管理这种情况,我仍然不明白 Mongoose 的目的是什么,如果有两个人,save() 系统就没用了做类似的动作肯定会在每个网站上发生......感谢您的回复,我会重构一切;)
请记住,Mongoose 确实使用原子 update
调用实现了 save
,只有 $set
s 文档中您实际更改的字段,所以它不像您那么糟糕重新可能在想。数组操作会给您带来最大的麻烦(这就是 Mongoose 添加versioning 的原因),但无论如何您都需要意识到发生了什么。
【参考方案1】:
正如您在此处所言,这不是处理数据更新的最佳方式。如果您考虑您要求做的事情,它基本上可以归结为:
-
从数据库中获取一个对象。
更新代码中的属性。
保存该数据,但不保证有其他修改。
因此,您需要尽可能避免这种模式并遵循常识,即您只需更改当前未设置为该值的现有值。因此,这意味着只需使用 $set
等运算符处理“更新”类型的语句:
db.Server.findOneAndUpdate(
"_id": refernce.server, "anything": "$ne": "ahah" ,
"$set": "anything": "ahah" ,
function(err,server)
if ( server != null )
// then something was actually found and modified
// so server now is the updated document
);
这意味着您将丢弃 mongoose 的任何字段验证或其他保存挂钩,但它是一种“原子”形式的更新,因为读取和写入不是单独的操作,这就是您当前的实现方式。
如果您希望实现某种类型的“锁定”,那么类似的方法是您最好的方法。因此,如果您想在文档上设置“状态”以显示某人当前正在编辑它,那么请维护一个字段来执行此操作并将其构建到您的查询中。
对于“阅读”文档并获取要呈现给“编辑”的信息,您可以执行以下操作:
db.Server.findOneAndUpdate(
"$_id": docId, "locked": false ,
"$set": "locked": true ,
function(err,document)
);
这意味着当有人“抓取”编辑时,随后的操作将无法这样做,因为他们正在寻找锁定状态为 false
的文档,而它不再是。将您的编辑作为“保存”提交时,同样的原则也适用,正好相反:
db.Server.findOneAndUpdate(
"$_id": docId, "locked": true ,
"$set": "locked": false ,
function(err,document)
);
您始终可以执行更高级的操作,例如保存的修订版或通过操作或任何其他形式的处理获得版本号。但一般来说,您应该根据自己的需要自行管理
【讨论】:
最后一个解决方案的唯一问题是,如果另一个人真的需要在“第一个”更改数据之后更改数据,“锁定”状态将中断该过程,并且可以使其他冲突..无论如何都是一个好技巧,我将更改我的代码并尝试以这种方式使用 mongo ;)【参考方案2】:我刚刚意识到我发布了一篇关于堆栈溢出的类似帖子。你可以在这里找到帖子: How to read/write a document in parallel execution with mongoDB/mongoose
在这篇文章中,有人告诉我在内存中保留一些日期以避免这种行为。这就是我所做的并且效果很好。但如果您使用多进程,则需要找到一种在进程之间共享内存的方法。
【讨论】:
以上是关于Mongoose 异步多次保存冲突的主要内容,如果未能解决你的问题,请参考以下文章