如何解决MongoDB中缺less事务的问题?

我知道这里有类似的问题,但是他们要么告诉我 ,如果我需要事务或者使用primefaces操作或者两阶段提交,就要回到常规的RDBMS系统。 第二个解决scheme似乎是最好的select。 第三,我不想跟随,因为看来很多事情可能会出错,我不能在各个方面进行testing。 我很难重构我的项目来执行primefaces操作。 我不知道这是否来自我有限的观点(我迄今为止只使用过SQL数据库),还是实际上无法完成。

我们想在我们公司试用MongoDB。 我们select了一个相对简单的项目 – 一个短信网关。 它允许我们的软件发送SMS消息到蜂窝networking,网关完成肮脏的工作:实际上通过不同的通信协议与提供商进行通信。 网关还pipe理消息的计费。 每个申请服务的客户都必须购买一些信用。 发送信息时系统自动降低用户的余额,如果余额不足,则拒绝访问。 另外因为我们是第三方短信服务提供商的客户,我们也可能有自己的余额。 我们也必须跟踪这些。

我开始考虑如何降低一些复杂性(外部计费,排队短信发送),如何使用MongoDB存储所需的数据。 来自SQL世界,我会为用户创build一个单独的表,另一个用于SMS消息,另一个用于存储关于用户余额的事务。 比方说,我为MongoDB中的所有人创build了单独的集合。

在这个简化的系统中,想象一下使用以下步骤的SMS发送任务:

  1. 检查用户是否有足够的余额; 拒绝访问,如果没有足够的信用

  2. 将消息发送并存储在SMS收集中,具体细节和成本(在实时系统中,消息将具有status属性,并且任务将会拿起它来交付并根据其当前状态来设置SMS的价格)

  3. 通过发送消息的成本来减less用户的余额

  4. 将事务logging在事务集合中

现在有什么问题? MongoDB只能在一个文档上进行primefaces更新。 在之前的stream程中,可能会发生某种错误,并将消息存储在数据库中,但用户的余额不会更新和/或事务未被logging。

我想出了两个想法:

  • 为用户创build一个集合,并将余额作为字段,与用户相关的交易和消息作为子文档存储在用户的文档中。 因为我们可以自动更新文件,这实际上解决了交易问题。 缺点:如果用户发送很多短消息,文档的大小可能会变大,可能达到4MB的文档限制。 也许我可以在这种情况下创build历史文档,但我不认为这是一个好主意。 另外我不知道如果我把越来越多的数据推送到同一个大文件系统会有多快。

  • 为用户创build一个集合,为事务创build一个集合。 可以有两种交易:正余额变化的信用卡购买和负余额变化的消息 。 交易可能有一个子文件; 例如在发送消息中可以将SMS的细节embedded到事务中。 缺点:我不存储当前的用户余额,所以每次用户试图发送消息时都要计算它是否可以通过消息。 恐怕这个计算可能会随着存储事务数量的增长而变慢。

我有点困惑要select哪种方法。 还有其他解决scheme吗? 我无法在网上find任何有关如何解决这些问题的最佳实践。 我想很多想要熟悉NoSQL世界的程序员在开始时都面临类似的问题。

看看这个 ,由Tokutek。 他们为Mongo开发一个插件,不仅能够保证交易,而且能够提高性能。

没有交易生活

事务支持ACID属性,但尽pipeMongoDB中没有事务,但我们确实有primefaces操作。 那么,primefaces操作就意味着当你处理一个单独的文档时,这个工作就会在别人看到文档之前完成。 他们会看到我们所做的所有更改或者没有任何更改。 使用primefaces操作,通常可以完成我们在关系数据库中使用事务完成的同样的事情。 原因在于,在关系数据库中,我们需要对多个表进行更改。 通常需要join的表格,所以我们想要一次完成。 要做到这一点,由于有多个表,我们将不得不开始一个事务,并执行所有这些更新,然后结束事务。 但是对于MongoDB ,我们要embedded数据,因为我们要把它们预先join到文档中,而且他们是这些有层次结构的丰富的文档。 我们经常可以完成同样的事情。 例如,在博客的例子中,如果我们想要确保自己更新博客文章,我们可以这样做,因为我们可以一次更新整个博客文章。 就像是一堆关系表一样,我们可能不得不打开一个事务,以便更新后期收集和评论集合。

那么我们可以在MongoDB采取哪些方法来克服交易缺失?

  • 重组 – 重构代码,以便我们在单个文档中工作,并利用我们在该文档中提供的primefaces操作。 如果我们这样做,那么通常我们都已经设定好了。
  • 在软件中实现 – 我们可以通过创build关键部分来实现软件locking。 我们可以build立一个testing,testing和设置使用查找和修改。 如果需要,我们可以build立信号量。 从某种意义上说,无论如何,大世界都是这样。 如果我们想一想,如果一家银行需要把钱转移到另一家银行,他们就不是生活在同一个关系系统里。 而且他们每个人都有自己的关系数据库。 而且即使我们不能在这些数据库系统之间开始交易和结束交易,他们也必须能够协调这一操作,只能在一个银行内的一个系统内进行。 所以软件肯定有办法解决这个问题。
  • 容忍 – 在现代Web应用程序和其他大量数据应用程序中经常使用的最后一种方法是容忍一点不一致。 举个例子,如果我们在Facebook上谈论一个朋友饲料,大家是否同时看到你的墙更新并不重要。 如果一个人有几个人在后面跳了几秒钟,他们就赶上了。 在许多系统devise中,一切都保持完全一致,并且每个人都拥有完全一致和相同的数据库视图,这通常并不重要。 所以我们可以简单地容忍一点点的不一致,这是暂时的。

UpdatefindAndModify$addToSet (在更新中)& $push (更新内)操作在单个文档中primefaces操作。

把它带到这个地步:如果事务完整性是必须的,那么不要使用MongoDB,而只使用支持事务的系统组件。 在组件之上构build某些东西非常困难,以便为不符合ACID的组件提供类似ACID的function。 根据不同的使用情况,以某种方式将操作分为事务性和非事务性操作是有意义的。

现在有什么问题? MongoDB只能在一个文档上进行primefaces更新。 在之前的stream程中,可能会发生某种错误,并且将消息存储在数据库中,但用户的余额不会减less和/或事务未被logging。

这不是一个真正的问题。 您提到的错误是逻辑(错误)或IO错误(networking,磁盘故障)。 这种types的错误可能会使交易存储和事务存储处于不一致的状态。 例如,如果已经发送了短信,但是存储短信错误发生了 – 不能回滚短信发送,这意味着不会被logging,用户余额不会减less等。

这里真正的问题是用户可以利用竞争条件,并发送比他的余额允许更多的消息。 这也适用于关系型数据库pipe理系统(RDBMS),除非你使用平衡字段locking(这将是一个很大的瓶颈)在事务内发送短信。 作为一个可能的解决scheme,MongoDB将首先使用findAndModify来减less余额并进行检查,如果是负数,则不允许发送和退还金额(primefaces增量)。 如果是肯定的,继续发送,如果它没有退还金额。 余额历史logging集合也可以维护以帮助修复/validation平衡字段。

该项目很简单,但你必须支持交易付款,这使得整个事情变得困难。 因此,例如,一个拥有数百个馆藏(论坛,聊天,广告等等)的复杂门户系统在某种程度上更简单一些,因为如果你失去了一个论坛或聊天logging,没有人真正关心。 另一方面,如果您失去了一个严重问题的付款交易。

所以,如果你真的想要一个MongoDB的试点项目,select一个在方面很简单的项目。

由于正当的原因,MongoDB中没有事务。 这是使MongoDB更快的事情之一。

在你的情况下,如果交易是必须的,mongo似乎不适合。

可能是RDMBS + MongoDB,但是这会增加复杂性,并且会增加pipe理和支持应用程序的难度。