随着实时应用程序和物联网(IoT)设备的使用,以及非结构化数据资产指数级增长,越来越多的组织正在转向NoSQL数据库。实际上,预计到2032年,NoSQL市场将达到745亿美元,从2024年到2032年的增长率(复合年增长率)为24.9%(IMARC集团,2024年)。
鉴于NoSQL数据库管理系统(DBMS)能够有效管理大型、多样化的数据集以及相关的大数据分析,这一增长并不令人惊讶。然而,许多人仍然认为NoSQL DBMS无法满足许多组织的关键需求——ACID事务管理和合规性。好消息是,一些NoSQL DBMS确实可以做到这一点!
在本文中,我们将讨论ACID事务是什么,ACID事务属性,为什么这些事务很重要,以及NoSQL DBMS中的ACID事务示例。
目录
在最基本层面上,数据库事务是一组数据库读和写操作,这些操作已经根据DBMS的定义成功完成(例如,定义的事务标准)。主要有两种类型的交易
单笔交易:单笔交易是指一系列一个或多个数据库操作,导致一个动作成功完成的操作序列。一旦完成,该交易将被接受,并可在交易日志中找到。单笔交易的常见例子是从ATM取款。
多笔交易:多笔交易,有时称为分布式交易,由多个相互依赖的交易组成,这些交易分布在不同的数据库和系统(例如,分布式系统)中。这些交易的记录也存在于交易日志中。这些交易的例子包括从一个账户向另一个账户转账或雇主为新员工发放带有照片的安全徽章。
需要注意的是,一些交易必须遵守严格的数据完整性(例如,数据是完整和正确的)和数据一致性(例如,值在所有表/数据库中相同)标准。这种情况通常涉及信托责任或合规性。例子包括商业银行、投资经纪和法律结算。在这些情况下,仅仅遵守DBMS定义的标准是不够的,需要ACID事务。
ACID代表原子性、一致性、隔离性和持久性(ACID)。ACID属性共同确保即使在发生意外错误的情况下,一组数据库操作(在事务中组合在一起)也能使数据库处于有效状态。此外,ACID事务提供了许多监管机构要求的交易保证级别。
以下是对每个ACID事务元素的概述,以及NoSQL文档数据库如何处理这些ACID元素的描述。为了本文的目的,将使用MongoDB Atlas。
原子性保证事务中的所有命令作为一个单一单元处理,要么全部成功,要么全部失败。这在系统故障或断电的情况下很重要,如果交易没有完全处理,则将被丢弃,数据库将保持其数据完整性。
在MongoDB中,写操作在单个文档级别上是原子的,即使该操作修改了一个文档内的多个嵌入式文档。对于需要读取和写入多个文档的原子性(在单个集合或多个集合中)的情况,MongoDB支持分布式事务,包括对副本集和分片集群的事务。
一致性保证事务中做出的更改在整个数据库系统(例如,节点)中填充,并且与DBMS约束一致。如果交易在不一致的状态下会负面影响数据一致性,则整个交易将失败。
MongoDB如何处理一致性MongoDB提供灵活的数据规范化或复制的选项来优化应用程序。如果数据在模式中被复制,开发人员必须决定如何保持多个集合中复制的数据一致性。某些应用程序需要立即使复制的数据保持一致,而其他应用程序可以容忍读取陈旧的数据。以下是一些示例
注意:了解更多关于数据一致性的信息。
每个事务与其他事务隔离,以防止数据冲突。这也有助于数据库操作,涉及管理多个条目和多级事务。例如,如果两个用户试图修改相同的数据(甚至相同的交易),DBMS使用称为锁管理器的机制来暂停其他用户,直到第一个用户所做的更改完成。
MongoDB采用了一种称为快照隔离的技术(例如,每个事务似乎在事务开始时对数据库的个人快照进行操作)。事务可以从事务开始时提交的“快照”数据中读取数据,任何冲突的更新都将导致事务中止。
此外,MongoDB事务支持事务级读取关注和事务级写入关注。客户端可以设置适当的读取和写入关注级别,最严格的是快照读取关注与多数写入关注的组合。多数写入关注意味着写入操作已持久地提交到计算出的多数数据承载节点(由开发者配置)。
持久性保证一旦事务完成并将更改写入数据库,它们就会持久化。这确保了即使在系统故障(如崩溃或断电)的情况下,系统中的数据也将持续存在。持久性的概念是数据可靠性的关键要素。
MongoDB创建一个OpLog,其中包含每个“写入”的磁盘位置和字节更改。如果在写入事务期间发生不可预见的事件(例如断电),则在系统启动时可以使用OpLog重放任何在关闭之前未刷新到磁盘的写入。此外,操作在OpLog中更改后再写入,以便它们是幂等的,可以重试多次。默认情况下,事务或“写入”每60秒大约刷新到磁盘一次。
ACID事务有助于维护数据完整性和可靠性,同时确保受政府或行业规范约束的关键数据(例如,银行账户、股票组合)符合要求标准。此外,ACID兼容性通常是实现数据复制和在分布式数据库系统中实现高可用性的先决条件。
使用NoSQL文档数据库MongoDB Atlas,以下是一个如何处理ACID多文档事务以及ACID事务如何保证符合最小ACID属性标准的示例。
假设您正在构建一个功能,用于将资金从一个银行账户转移到另一个账户,其中每个账户都是一个单独的记录。如果资金成功从源账户扣除但从未贷记到目标账户,就会产生严重的会计问题。相反,如果目标账户已贷记但源账户从未扣除,则会出现另一个严重的会计问题。
该图展示了ACID属性如何影响银行账户之间转账的流程。
这两个写操作必须同时发生或同时不发生,以保持系统和其数据的一致性。此外,这意味着如果事务中的任何命令失败,数据库必须回滚(例如,撤销)它在事务过程中写入的所有更改。
注意:要了解更多信息,请访问Node.js 快速入门 GitHub 仓库以获取完整代码示例并自行运行。
在处理分布式系统中的多文档事务时,请记住,性能开销可能会影响资源约束和性能目标。此外,由于数据库必须“锁定”所涉及的资源以防止并发写入相互干扰(例如,事务失败),尝试写入数据的其他客户端可能会因等待事务完成而受阻,这可能会影响应用程序延迟和用户体验。
MongoDB的文档模型允许相关数据在单个文档中存储。文档模型与原子文档更新相结合,消除了在大多数用例中需要事务的需求。尽管如此,在某些情况下,真正的多文档、多集合MongoDB事务是最佳选择。
MongoDB事务的工作方式与其他数据库中的事务类似。要使用事务,通过驱动程序启动MongoDB会话。然后,使用该会话执行您的数据库操作组。您可以在多个文档、集合和分片中运行任何CRUD(创建、读取、更新和删除)操作。
有关实现事务的特定代码示例,请查看MongoDB开发者中心的快速入门教程。
请访问MongoDB驱动程序文档,获取MongoDB官方支持的每种语言的特定指南。您还可以查看事务最佳实践和生产注意事项列表。
需要事务的应用程序通常涉及不同实体之间的值交换。这些通常是“记录系统”或“业务线”应用程序。
可能从多文档事务中受益的应用程序示例包括
将资金从一个账户转移到另一个账户的系统(例如,银行应用程序、支付处理系统、交易平台)。
供应链和预订系统,其中商品和服务所有权从一个实体转移到另一个实体。
计费系统,用于存储详细信息记录以及汇总记录。
通常建议以这种方式建模数据,以便一起访问的数据存储在一起。以这种方式建模数据时,不仅可以获得更好的性能,而且不需要进行事务。
对于确实需要事务的应用程序,请遵循以下最佳实践
想要了解更多吗? MongoDB Atlas是MongoDB的完全托管数据库服务,它是开始使用MongoDB的最简单方法。通过创建免费的MongoDB Atlas集群开始使用事务。