MongoDB数据库两阶段提交实现事务的方法详解

  • A+
所属分类:MongoDB

本文实例讲述了MongoDB数据库两阶段提交实现事务的办法。分享给年夜家供年夜家参考,详细如下:

MongoDB数据库中操作单个文档老是原子性的,然而,涉及多个文档的操作,通常被作为一个“事务”,而不是原子性的。由于文档可所以相称繁杂而且包括多个嵌套文档,单文档的原子性对很多现实用例提供了支撑。只管单文档操作是原子性的,在某些环境下,必要多文档事务。在这些环境下,使用两阶段提交,提供这些类型的多文档更新支撑。由于文档可以表现为Pending数据和状况,可以使用一个两阶段提交确保数据是同等的,在一个差错的环境下,事务前的状况是可规复的。

事务最常见的例子因此靠得住的方式从A账户转账到B账户,在关系型数据库中,此操作将从A账户减失落金额和给B账户增长金额的操作封装在单个原子事务中。在MongoDB中,可以使用两阶段提交到达雷同的后果。本文中的所有示例使用mongo shell与数据库进行交互,并假设有两个聚拢:起首,一个名为accounts的聚拢存储每个账户的文档数据,另一个名为transactions的聚拢存储事务自己。

起首创立两个名为A和B的账户,使用下面的敕令:

使用find()办法验证这两个操作已经胜利:

mongo会返回两个相似下面的文档:

事务进程:

设置事务初始状况initial:

经由过程插入下面的文档创立transaction聚拢,transaction文档持有源(source)和目的(destination),它们引用自accounts聚拢文档的字段名,以及value字段表现转变balance字段数目的数据。末了,state字段反映事务确当前状况。
复制代码 代码如下:db.transactions.save({source: "大众A"大众, destination: "大众B"大众, value: 100, state: "大众initial"大众})

验证这个操作已经胜利,使用find()

这个操作会返回一个相似下面的文档:
复制代码 代码如下:{ "大众_id"大众 : ObjectId("大众4d7bc7a8b8a04f5126961522"大众), "大众source"大众 : "大众A"大众, "大众destination"大众 : "大众B"大众, "大众value"大众 : 100, "大众state"大众 : "大众initial"大众 }

切换事务到Pending状况:

在改动accounts聚拢记载之前,将事务状况从initial设置为pending。使用findOne()办法将transaction文档赋值给shell会话中的局部变量t:

变量t创立后,shell将返回它的值,将会看到如下的输出:
复制代码 代码如下:{ "大众_id"大众 : ObjectId("大众4d7bc7a8b8a04f5126961522"大众), "大众source"大众 : "大众A"大众, "大众destination"大众 : "大众B"大众, "大众value"大众 : 100, "大众state"大众 : "大众initial"大众 }

使用update()转变state的值为pending:

find()操作将返回transaction聚拢的内容,相似下面:
复制代码 代码如下:{ "大众_id"大众 : ObjectId("大众4d7bc7a8b8a04f5126961522"大众), "大众source"大众 : "大众A"大众, "大众destination"大众 : "大众B"大众, "大众value"大众 : 100, "大众state"大众 : "大众pending"大众 }

将事务利用到两个账户:

使用update()办法利用事务到两个账户。在update()查询中,前提pendingTransactions:{$ne:t._id}阻止事务更新账户,假如账户的pendingTransaction字段包括事务t的_id:

find()操作将返回accounts聚拢的内容,如今应该相似于下面的内容:

设置事务状况为committed:

使用下面的update()操作设置事务的状况为committed:

find()操作发还transactions聚拢的内容,如今应该相似下面的内容:
复制代码 代码如下:{ "大众_id"大众 : ObjectId("大众4d7bc7a8b8a04f5126961522"大众), "大众destination"大众 : "大众B"大众, "大众source"大众 : "大众A"大众, "大众state"大众 : "大众committed"大众, "大众value"大众 : 100 }

移除pending事务:

使用下面的update()操作从accounts聚拢中移除pending事务:

find()操作返回accounts聚拢内容,如今应该相似下面内容:

设置事务状况为done:

经由过程设置transaction文档的state为done完成事务:

find()操作返回transaction聚拢的内容,此时应该相似下面:
复制代码 代码如下:{ "大众_id"大众 : ObjectId("大众4d7bc7a8b8a04f5126961522"大众), "大众destination"大众 : "大众B"大众, "大众source"大众 : "大众A"大众, "大众state"大众 : "大众done"大众, "大众value"大众 : 100 }

从失败场景中规复:

最紧张的部门不是上面的典型例子,而是从各类失败场景中规复未完成的事务的可能性。这部门将概述可能的失败,并提供办法从这些变乱中规复事务。这里有两种类型的失败:

1、所有产生在第一步(即设置事务的初始状况initial)之后,但在第三步(即利用事务到两个账户)之前的失败。为了还原事务,利用应该获取一个pending状况的transaction列表而且从第二步(即切换事务到pending状况)中规复。

2、所有产生在第三步之后(即利用事务到两个账户)但在第五步(即设置事务状况为done)之前的失败。为了还原事务,利用必要获取一个committed状况的事务列表,而且从第四步(即移除pending事务)规复。

是以利用法式老是可以或许规复事务,终极到达一个同等的状况。利用法式开端捕捉到每个未完成的事务时运行下面的规复操作。你可能还愿望按期运行规复操作,以确保数据处于同等状况。杀青同等状况所必要的光阴取决于利用法式必要多永劫间规复每个事务。

回滚:

在某些环境下可能必要“回滚”或“取消”事务,当利用法式必要“撤消”该事务时,或者是由于它永久必要规复当此中一个帐户不存在的环境下,或结束现有的事务。这里有两种可能的回滚操作:

1、利用事务(即第三步)之后,你已经完全提交事务,你不该该回滚事务。相反,创立一个新的事务,切换源(源)和目的(destination)的值。

2、创立事务(即第一步)之后,在利用事务(即第三步)之前,使用下面的处置进程:

设置事务状况为canceling:

起首设置事务状况为canceling,使用下面的update()操作:

撤销事务:

使用下面的操作次序从两个账户中撤销事务:

find()操作返回acounts聚拢的内容,应该相似下面:

设置事务状况为canceled:

末了,使用下面的update()状况将事务状况设置为canceled:

参考材料:http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits/

愿望本文所述对年夜家MongoDB数据库法式设计有所赞助。

您可能感兴致的文章:

mongoDB 4.0事务回滚的酸楚历程探讨MongoDB各类查询操作详解mongodb中使用distinct去重的简单办法PHP中MongoDB数据库的衔接、添加、改动、查询、删除等操作实例mongodb 添加用户及权限设置详解1亿笔记录的MongoDB数据库随机查询机能测试mongodb 查看数据库和表年夜小MongoDB下依据数组年夜小进行查询的办法Linux体系下MongoDB的简单安装与根本操作MongoDB 语法使用小结mongodb与mysql敕令具体对照

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: