【问题标题】:Mongoose asynchronous multiple save conflictsMongoose 异步多次保存冲突
【发布时间】: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)

我找了好久没找到答案:(

希望你能理解我的问题;)谢谢!

【问题讨论】:

  • 那么如何使用 mongo 建立一个有人员的网站? ...
  • 您可以构建架构,以便您可以使用原子update 调用来完成所有文档修改。
  • Tricky ...如果他们无法管理这种情况,我仍然不明白 Mongoose 的目的是什么,如果有两个人,save() 系统就没用了做类似的动作肯定会在每个网站上发生......感谢您的回复,我会重构一切;)
  • 请记住,Mongoose 确实使用原子 update 调用实现了 save,只有 $sets 文档中您实际更改的字段,所以它不像您那么糟糕重新可能在想。数组操作会给您带来最大的麻烦(这就是 Mongoose 添加versioning 的原因),但无论如何您都需要意识到发生了什么。

标签: javascript node.js mongodb mongoose socket.io


【解决方案1】:

正如您在此处所言,这不是处理数据更新的最佳方式。如果您考虑您要求做的事情,它基本上可以归结为:

  1. 从数据库中获取一个对象。
  2. 更新代码中的属性。
  3. 保存该数据,但不保证有其他修改。

因此,您需要尽可能避免这种模式并遵循常识,即您只需更改当前未设置为该值的现有值。因此,这意味着只需使用 $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

在这篇文章中,有人告诉我在内存中保留一些日期以避免这种行为。这就是我所做的并且效果很好。但如果您使用多进程,则需要找到一种在进程之间共享内存的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-15
    • 1970-01-01
    • 2015-02-06
    • 1970-01-01
    • 2021-10-16
    • 1970-01-01
    • 2012-07-18
    • 1970-01-01
    相关资源
    最近更新 更多