【问题标题】:How to move money with MongoDB?如何使用 MongoDB 转移资金?
【发布时间】:2013-11-22 12:33:53
【问题描述】:
Account has embedded
  Transactions
    amount (positive for received transactions, negative for outgoing transactions)

用户想要汇款。我们需要计算账户的余额来检查是否有足够的钱。在伪代码中:

send_money(amount)
  balance = sum(account's all transactions) // Mongo Query 1
  if (amount <= balance)
    add a new transaction to account // Mongo Query 2

但是两个并发的 mongo 连接是否可能都通过查询 1 并继续进行查询 2?假设用户的余额为 1,两个价值 1 的并发汇款请求同时通过查询 1 并成功添加到交易中。实际上,用户的余额为 -1。

如何预防?

【问题讨论】:

  • 看起来是个不错的解决方案。我想知道使用单独的锁集合与 Update If Current 模式相比如何?
  • 如果当前更新将仅适用于同一个文档,而不适用于多个文档
  • 更新如果当前只是旨在确保您更新最新的文档,它不是跨许多文档的事务,例如您正在寻找的文档

标签: mongodb transactions locking


【解决方案1】:

当您的用例需要跨多个文档的事务时,MongoDB 通常不适合它,因为当多个文档受到影响时,它不支持原子操作。

一个可能的解决方法是two-phase-commit 模型。

这基本上意味着您首先将您想要对每个文档执行的操作作为附加字段添加到它的描述。然后,您对每个应用该操作并删除描述的文档执行原子操作。之后通过查询文档来确认这些步骤中的每一个,并且事务的每个步骤都由附加的待处理事务集合中的第三个文档记录。这允许您检查待处理的事务并将它们回滚。

这种方法很难实现,而且开销很大。在实现此功能之前,您应该认真考虑是否真的有充分的理由不使用具有本机事务支持的数据库系统。

【讨论】:

  • 如果当前模式更新呢?是不是更轻量级了?
  • @randomguy 此答案是对您对 PKD 答案的评论的反应,其中您询问了当两个集合受到影响时该怎么办。 UpdateIfCurrent 模式是另一种情况:两个线程试图更改同一个对象。这是一个更简单的解决方案。
【解决方案2】:

如何使用此处概述的 Update If Current 模式:http://docs.mongodb.org/manual/tutorial/isolate-sequence-of-operations/ 以及该页面底部附近讨论的建议“将版本变量添加到应用程序在每次更新操作时递增的文档”?除了交易数组之外,您可能还需要在文档中的某个字段中跟踪当前余额。因此,您的更新部分可能需要您的版本字段中的 $inc 为 1,余额字段中的 +/- 金额的 $inc 以及数组中新交易元素的 $push。

【讨论】:

  • 如果事务位于单独的集合中,则 Update If Current 模式是否有效?
  • 您最初的问题是询问如果两个并发客户端线程尝试更新 same 文档会发生什么。如果您真的在问“单笔交易如何以原子方式跨越(1)从一个文件中借记钱和(2)将钱贷记到单独的文件中”,那么您将需要一种类似于 2PC 的方法,例如Sammaye 链接到。
【解决方案3】:

明年夏天以后,这将不再是问题。 MongoDB 将在 4.0 版本中添加对多文档事务的支持,因此我们将在 RBDMS 系统等多文档事务中提供 ACID 保证。

现在,MongoDB 用例将适合所有您可以使用的用例!

查看此帖子:https://www.mongodb.com/blog/post/multi-document-transactions-in-mongodb?jmp=community

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-04
    • 2017-10-23
    • 2020-01-19
    • 2017-12-13
    相关资源
    最近更新 更多