mongodb使用两阶段提交实现事务
2017-04-01 00:00
483 查看
1.mongodb实现事务的方法
mongoDB数据库中操作单个文档总是原子性的,然而,涉及多个文档的操作,通常被作为一个“事务”,而不是原子性的。因为文档可以是相当复杂并且包含多个嵌套文档,单文档的原子性对许多实际用例提供了支持。尽管单文档操作是原子性的,在某些情况下,需要多文档事务。在这些情况下,使用两阶段提交,提供这些类型的多文档更新支持。MongoDB的两阶段提交实际上是通过使用另外一个表存储中间状态控制事务的原子性和一致性。官网解释:https://docs.mongodb.com/manual/tutorial/perform-two-phase-commits/
2.mongodb实现事务的例子
以从A账户转100给B帐户作为例子来看如何通过两阶段提交的方式实现事务
2.1 转账初始化
a.初始化两个帐号A,B:
b.使用另外一个表初始化事务状态(包含两个账户_id,转账金额,当前状态,上次修改时间):
2.2 开始事务
a.设置事务状态为pending状态并设置修改时间:
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1,如果nMatched和nModified是0,重新执行2.1步骤开启一个新的事务
b.更新账户A减少100,加入了查询条件pendingTransactions,通过事务_id避免事务的重复执行
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
c.更新账户B增加100,加入了查询条件pendingTransactions,通过事务_id避免事务的重复执行
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
2.3 更新事务已经生效
a.更新事务执行状态为已生效以及时间为当前时间
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
b.更新A账户并删掉依赖的事务_id
c.更新B账户并删掉依赖的事务_id
2.4 更新事务为已完成
a.更新事务执行状态为已完成以及时间为当前时间
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
2.5 事务失败后的恢复
2.5.1 pending阶段失败的恢复
如果在上面的2.2步骤中的事务失败了,当前状态是pending状态,恢复方式是重新执行2.2步骤中的更新用户账户信息步骤,例如每隔三十分钟检查之前还处于pending的事务,重新执行2.2步骤中的更新用户账户信息步骤:
2.5.2 applied阶段失败的恢复
如果在上面2.3步骤中的事务失败了,当前状态是applied状态,恢复方式是重新执行2.3步骤中的删除账户依赖的事务_id,例如每隔三十分钟检查之前还处于pending的事务,重新执行2.3步骤中的删除账户依赖的事务_id:
2.6 事务的回滚
2.6.1 pending阶段的回滚
如果事务处在pending阶段需要回滚,需要执行以下步骤
a.更新事务状态为正在取消以及修改时间:
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
b.账户B执行与以前相反的操作,增加pendingTransactions条件的目的是只回滚已经执行过的操作:
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
c.账户A执行与以前相反的操作,增加pendingTransactions条件的目的是只回滚已经执行过的操作:
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
d.更新事务执行状态为已取消:
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
2.6.2 applied阶段的回滚
如果事务处在applied阶段需要回滚,需要执行以下步骤
a.把当前事务执行结束
b.再开启一个新的事务,把事务执行的源和目标互换,执行一个相反的事务
mongoDB数据库中操作单个文档总是原子性的,然而,涉及多个文档的操作,通常被作为一个“事务”,而不是原子性的。因为文档可以是相当复杂并且包含多个嵌套文档,单文档的原子性对许多实际用例提供了支持。尽管单文档操作是原子性的,在某些情况下,需要多文档事务。在这些情况下,使用两阶段提交,提供这些类型的多文档更新支持。MongoDB的两阶段提交实际上是通过使用另外一个表存储中间状态控制事务的原子性和一致性。官网解释:https://docs.mongodb.com/manual/tutorial/perform-two-phase-commits/
2.mongodb实现事务的例子
以从A账户转100给B帐户作为例子来看如何通过两阶段提交的方式实现事务
2.1 转账初始化
a.初始化两个帐号A,B:
db.accounts.insert( [ { _id: "A", balance: 1000, pendingTransactions: [] }, { _id: "B", balance: 1000, pendingTransactions: [] } ] )
b.使用另外一个表初始化事务状态(包含两个账户_id,转账金额,当前状态,上次修改时间):
db.transactions.insert( { _id: 1, source: "A", destination: "B", value: 100, state: "initial", lastModified: new Date() } )
2.2 开始事务
a.设置事务状态为pending状态并设置修改时间:
var t = db.transactions.findAndModify( { query: { state: "initial" }, update: { $set: { state: "pending"}, $currentDate: { lastModified: true } }, new: true } )
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1,如果nMatched和nModified是0,重新执行2.1步骤开启一个新的事务
b.更新账户A减少100,加入了查询条件pendingTransactions,通过事务_id避免事务的重复执行
db.accounts.update( { _id: t.source, pendingTransactions: { $ne: t._id } }, { $inc: { balance: -t.value }, $push: { pendingTransactions: t._id } } )
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
c.更新账户B增加100,加入了查询条件pendingTransactions,通过事务_id避免事务的重复执行
db.accounts.update( { _id: t.destination, pendingTransactions: { $ne: t._id } }, { $inc: { balance: t.value }, $push: { pendingTransactions: t._id } } )
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
2.3 更新事务已经生效
a.更新事务执行状态为已生效以及时间为当前时间
db.transactions.update( { _id: t._id, state: "pending" }, { $set: { state: "applied" }, $currentDate: { lastModified: true } } )
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
b.更新A账户并删掉依赖的事务_id
db.accounts.update( { _id: t.source, pendingTransactions: t._id }, { $pull: { pendingTransactions: t._id } } )
c.更新B账户并删掉依赖的事务_id
db.accounts.update( { _id: t.destination, pendingTransactions: t._id }, { $pull: { pendingTransactions: t._id } } )
2.4 更新事务为已完成
a.更新事务执行状态为已完成以及时间为当前时间
db.transactions.update( { _id: t._id, state: "applied" }, { $set: { state: "done" }, $currentDate: { lastModified: true } } )
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
2.5 事务失败后的恢复
2.5.1 pending阶段失败的恢复
如果在上面的2.2步骤中的事务失败了,当前状态是pending状态,恢复方式是重新执行2.2步骤中的更新用户账户信息步骤,例如每隔三十分钟检查之前还处于pending的事务,重新执行2.2步骤中的更新用户账户信息步骤:
var dateThreshold = new Date(); dateThreshold.setMinutes(dateThreshold.getMinutes() - 30); var t = db.transactions.findOne( { state: "pending", lastModified: { $lt: dateThreshold } } );
2.5.2 applied阶段失败的恢复
如果在上面2.3步骤中的事务失败了,当前状态是applied状态,恢复方式是重新执行2.3步骤中的删除账户依赖的事务_id,例如每隔三十分钟检查之前还处于pending的事务,重新执行2.3步骤中的删除账户依赖的事务_id:
var dateThreshold = new Date(); dateThreshold.setMinutes(dateThreshold.getMinutes() - 30); var t = db.transactions.findOne( { state: "applied", lastModified: { $lt: dateThreshold } } );
2.6 事务的回滚
2.6.1 pending阶段的回滚
如果事务处在pending阶段需要回滚,需要执行以下步骤
a.更新事务状态为正在取消以及修改时间:
db.transactions.update( { _id: t._id, state: "pending" }, { $set: { state: "canceling" }, $currentDate: { lastModified: true } } )
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
b.账户B执行与以前相反的操作,增加pendingTransactions条件的目的是只回滚已经执行过的操作:
db.accounts.update( { _id: t.destination, pendingTransactions: t._id }, { $inc: { balance: -t.value }, $pull: { pendingTransactions: t._id } } )
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
c.账户A执行与以前相反的操作,增加pendingTransactions条件的目的是只回滚已经执行过的操作:
db.accounts.update( { _id: t.source, pendingTransactions: t._id }, { $inc: { balance: t.value}, $pull: { pendingTransactions: t._id } } )
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
d.更新事务执行状态为已取消:
db.transactions.update( { _id: t._id, state: "canceling" }, { $set: { state: "cancelled" }, $currentDate: { lastModified: true } } )
如果更新成功,会返回WriteResult对象中的nMatched和nModified的值为1
2.6.2 applied阶段的回滚
如果事务处在applied阶段需要回滚,需要执行以下步骤
a.把当前事务执行结束
b.再开启一个新的事务,把事务执行的源和目标互换,执行一个相反的事务
相关文章推荐
- MongoDB两阶段提交实现事务
- MongoDB两阶段提交实现事务
- MongoDB两阶段提交实现事务
- 消息服务框架(MSF)应用实例之分布式事务三阶段提交协议的实现
- MySql使用存储过程实现事务的提交或者回滚
- PHP:分布式事务及两阶段提交方案实现思路
- MongoDB数据库两阶段提交实现事务的方法详解
- 浅析SQL Server实现分布式事务的两阶段提交协议2PC
- 分布式事务——使用消息队列消除两阶段提交
- 使用事务实现--转账问题:从0001账户转1000块到0002账户。打开"隐式事务":设置为开,删除表中数据,回滚!(默认情况为关,如果打开了则不自动提交,学要手动提交)
- 简单实现主从非约束表的事务处理提交(多表多记录)
- 使用事务与锁,实现一个用户取过的数据不被其他用户取到
- 使用Dojo实现页面不刷新提交数据时避免前台缓存的方法
- 使用Dojo实现页面不刷新提交数据
- 在C#中使用COM+实现事务控制
- 使用TransactionScope 实现事务管理
- 在C#中使用COM+实现事务控制
- 使用Ado.Net进行简单事务处理的四种实现及比较
- 使用事务与锁,实现一个用户取过的数据不被其他用户取到
- 使用事务与锁,实现一个用户取过的数据不被其他用户取到