暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MongoDB中的多文档ACID事务及其使用概述

原创 Onyancha Brian Henry 2020-01-02
4464

数据库系统必须保证数据的一致性和完整性,特别是在涉及关键数据时。这些方面是通过MongoDB中的ACID事务来实现的。在对数据库进行任何更新之前,ACID事务应满足一些定义的数据有效性规则,否则应中止该事务,并且不对数据库进行任何更改。所有数据库事务都被视为单个逻辑操作,在执行期间,数据库将处于不一致状态,直到提交更改为止。成功更改数据库状态的操作称为写事务,而不更新数据库但只检索数据的操作称为只读事务。ACID是原子性,一致性,隔离性和持久性的首字母缩写。

数据库是一种共享资源,可以由不同用户在不同时间或同一时间访问。因此,可能会发生并发事务,如果管理不善,它们可能会导致系统崩溃,硬件故障,死锁,数据库性能下降或同一事务的执行重复。

什么是ACID规则?

所有数据库系统都必须满足ACID属性,以保证数据完整性。

原子性

事务被视为可以完全成功或完全失败的单个操作单元。事务不能部分执行。如果咨询事务的任何条件失败,则整个事务将完全失败,并且数据库将保持不变。例如,如果要将资金从帐户X转移到Y,这里有两个交易,第一个交易是从X删除资金,第二个交易是在Y中记录资金。如果第一个交易失败,则整个交易将被中止。

一致性

发出操作时,在执行之前,数据库处于一致状态,并且应该在每次事务处理之后保持不变。即使有更新,事务也应始终使数据库进入有效状态,并保持数据库不变。例如,您不能删除已在另一个集合中作为外键引用的主键。所有数据都必须满足定义的约束,以防止非法交易破坏数据。

隔离性

并发运行的多个事务不会相互影响地被执行,并且如果要顺序执行它们的结果应该相同。当两个或多个事务修改MongoDB中的相同文档时,可能会发生冲突。数据库将在提交之前立即检测到冲突。获取文档锁的第一个操作将继续,而另一个操作将失败,并且将显示冲突错误消息。

持久性

这表明,一旦事务被提交,即使在由于电源中断或互联网断开等系统故障的情况下,也应始终保持更改。

MongoDB ACID交易

MongoDB是具有灵活架构的基于文档的NoSQL数据库。事务不是每一个写的操作都应该执行的操作,因为与单个文档写操作相比,它们会带来更高的性能成本。使用基于文档的结构和非规范化的数据模型,对事务的需求将降到最低。由于MongoDB允许文档嵌入,因此您不一定需要使用事务来满足写操作。

MongoDB 4.0版仅对副本集部署提供多文档事务支持,而4.2版可能会扩展对分片部署的支持(根据其发行说明)。

交易示例:

确保首先有一个副本集。假设您有一个名为app 的数据库,并且Mongo Shell中的集合用户运行以下命令:

$ mongos,您应该会看到类似 username:PRIMARY>的内容

$use app
 
$db.users.insert([{_id:1, name: ‘Brian’}, {_id:2, name: ‘Sheila’}, {_id:3, name: ‘James’}])

我们需要为我们的交易开始一个会话:

$db.getMongo().startSession() and you should see something like 
 
session { "id" : UUID("dcfa8de5-627d-3b1c-a890-63c9a355520c") }

通过此会话,我们可以使用以下命令使用事务添加更多用户

$session.startTransaction()
 
session.getDatabase(‘app’).users.insert({_id:4, name:  ‘Hitler’})

您将看到WriteResult({“ nInsterted”:2})

事务尚未提交,普通的 $ db.users.find({})将只给我们以前保存的用户。但是如果我们运行

$session.getDatabase(“app”).users.find()

最后添加的记录将在返回的结果中可用。要提交此事务,我们运行以下命令

$session.commitTransaction()

事务修改存储在内存中,这就是即使在失败后仍可在恢复时使用数据的原因。

MongoDB中的多文档ACID事务

这些是多语句操作,需要顺序执行而不会互相影响。对于上面的示例,我们可以创建两个事务,一个事务添加一个用户,另一个事务更新一个具有年龄范围的用户。即

$session.startTransaction()
 
   db.users.insert({_id:6, name “Ibrahim”})
 
   db.users.updateOne({_id:3 , {$set:{age:50}}})
 
session.commit_transaction()

可以将事务应用于针对一个或多个集合/数据库中包含的多个文档的操作。由于文档事务处理而引起的任何更改都不会影响无关的或不需要的工作负载的性能。在提交事务之前,未提交的写入既不会复制到辅助节点,也不能在事务外部读取。

MongoDB事务最佳实践

仅在WiredTiger存储引擎中支持多文档事务。如前所述,很少有应用程序需要事务处理,如果需要的话,我们应该尝试使其简短。否则,对于单个ACID事务,如果尝试执行过多的操作,则可能对WiredTiger缓存造成很大压力。自创建了最早的快照以来,始终指示缓存保持所有后续写入的状态。这意味着新写的操作将在整个事务期间累积在缓存中,并且仅在提交或中止当前在旧快照上运行的事务之后才刷新。为了在事务上获得最佳的数据库性能,开发人员应考虑:

  1. 始终在事务中修改少量文档。否则,您将需要将交易分为不同的部分,并以不同的批次处理文档。一次最多处理1000个文档。
  2. 暂时的异常(例如,等待选举主要和短暂的网络打may)可能会导致交易中止。如果出现定义的错误,开发人员应建立逻辑以重试事务。
  3. 从MongoDB提供的默认60秒开始,配置执行事务的最佳持续时间。此外,使用索引,以便可以在事务中快速访问数据。您还可以灵活地调整事务,以解决超时问题,方法是将其分为几批以允许其在时间限制内执行。
  4. 将您的事务分解为一小组操作,使其适合16MB的大小限制。否则,如果操作和操作日志说明一起超过了此限制,则事务将中止。
  5. 与实体有关的所有数据都应存储在单个丰富的文档结构中。这是为了减少要更改不同字段时要缓存的文档数量。

事务限制

  1. 您不能在事务内创建或删除集合。
  2. 事务无法写入上限集合
  3. 事务需要花费大量时间才能执行,并且它们会以某种方式降低数据库的性能。
  4. 交易大小限制为16MB,需要将其超过该大小的任何内容拆分为较小的交易。
  5. 使大量文档经受事务处理可能会对WiredTiger引擎施加过大压力,并且由于它依赖于快照功能,因此将在内存中保留大量未刷新的操作。这在数据库上产生了一些性能成本。

结论

MongoDB 4.0版引入了对副本集的多文档事务支持,以提高数据完整性和一致性。但是,使用 MongoDB时,很少有需要交易的应用程序。就交易概念而言,此功能存在一些局限性,使其相当不成熟。例如,不支持分片群集的事务,并且事务不能超过16MB的大小限制。数据建模为减少数据库中的事务提供了更好的结构。除非您处理特殊情况,否则最好避免在 MongoDB中进行事务处理。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论