//提交 private void CommitTransfer(TransactionDocument txn, TimeSpan maxTxnTime) { DateTime now = DateTime.Now.ToUniversalTime(); DateTime cutOff = now - maxTxnTime; //更新事务文档 FilterDefinitionBuilder <TransactionDocument> filterBuilder = Builders <TransactionDocument> .Filter; FilterDefinition <TransactionDocument> filter1 = filterBuilder.Eq(m => m._id, txn._id); FilterDefinition <TransactionDocument> filter2 = filterBuilder.Gt(m => m.Ts, cutOff); FilterDefinition <TransactionDocument> filter = filterBuilder.And(new FilterDefinition <TransactionDocument>[] { filter1, filter2 }); var update = Builders <TransactionDocument> .Update.Set(m => m.State, "commit"); UpdateResult updateResult = mongoDBService.DocumentUpdate(TransactionCollectionName, filter, update); bool isSuccess = updateResult.ModifiedCount > 0 && updateResult.ModifiedCount == updateResult.MatchedCount ? true : false; if (!isSuccess) { throw new Exception("修改事务文档失败"); } else { RetireTransaction(txn); } }
//准备转账 private TransactionDocument PrepareTransfer(double amt, string source, string destination) { string strGUID = System.Guid.NewGuid().ToString("N"); //类似e0a953c3ee6040eaa9fae2b667060e09 //创建事务文档 TransactionDocument tDoc = new TransactionDocument { _id = strGUID, //这个应该是随机生成的一个串 State = "new", Ts = DateTime.Now, Amt = amt, Src = source, Dst = destination }; //将事务文档插入事务集合 bool isSu = mongoDBService.Insert(TransactionCollectionName, tDoc); if (!isSu) { throw new Exception("构建事务文档失败!"); } FilterDefinitionBuilder <Account> filterBuilder = Builders <Account> .Filter; //更新source账户 FilterDefinition <Account> filterS = filterBuilder.Eq(m => m._id, source) & filterBuilder.Gte(m => m.Balance, amt); UpdateDefinition <Account> updateS = Builders <Account> .Update.Push(m => m.Txns, tDoc._id).Inc(m => m.Balance, -amt); UpdateResult updateResult = mongoDBService.DocumentUpdate(AccountsCollectionName, filterS, updateS); //检测更新是否成功 bool isSuccess = updateResult.ModifiedCount > 0 && updateResult.ModifiedCount == updateResult.MatchedCount? true:false; if (!isSuccess) { mongoDBService.Delete <TransactionDocument>(TransactionCollectionName, m => m._id == tDoc._id); throw new Exception("更新source账户失败"); } //更新destination账户 FilterDefinition <Account> filterD = filterBuilder.Eq(m => m._id, destination); var updateD = Builders <Account> .Update.Push(m => m.Txns, tDoc._id).Inc(m => m.Balance, amt); UpdateResult updateResultD = mongoDBService.DocumentUpdate(AccountsCollectionName, filterD, updateD); bool isSuccessD = updateResultD.ModifiedCount > 0 && updateResultD.ModifiedCount == updateResultD.MatchedCount ? true : false; if (!isSuccessD) { throw new Exception("更新destination账户失败"); } return(tDoc); }
public void Transfer(double amt, string source, string destination, TimeSpan maxTxnTime) { try { //准备转账 TransactionDocument txn = PrepareTransfer(amt, source, destination); CommitTransfer(txn, maxTxnTime); } catch (Exception ex) { Console.WriteLine(ex.Message); } }
//收回事务 //事务收回方法也是幂等的 private void RetireTransaction(TransactionDocument txn) { FilterDefinitionBuilder <Account> filterBuilder = Builders <Account> .Filter; FilterDefinition <Account> filter = filterBuilder.Eq(m => m._id, txn.Src);//source var update = Builders <Account> .Update.Pull(m => m.Txns, txn._id); mongoDBService.DocumentUpdate(AccountsCollectionName, filter, update); FilterDefinition <Account> filterD = filterBuilder.Eq(m => m._id, txn.Dst);//dest var updateD = Builders <Account> .Update.Pull(m => m.Txns, txn._id); mongoDBService.DocumentUpdate(AccountsCollectionName, filterD, updateD); mongoDBService.Delete <TransactionDocument>(TransactionCollectionName, m => m._id == txn._id); }
//回滚 //这里的回滚方法是“幂等的” private void RollbackTransfer(TransactionDocument txn) { //恢复账户信息 FilterDefinitionBuilder <Account> filterBuilder = Builders <Account> .Filter; FilterDefinition <Account> filter1 = filterBuilder.Eq(m => m._id, txn.Src);//source FilterDefinition <Account> filter2 = filterBuilder.Where(m => m.Txns.Contains(txn._id)); FilterDefinition <Account> filter = filterBuilder.And(new FilterDefinition <Account>[] { filter1, filter2 }); var update = Builders <Account> .Update.Inc(m => m.Balance, txn.Amt).Pull(m => m.Txns, txn._id); mongoDBService.DocumentUpdate(AccountsCollectionName, filter, update); FilterDefinition <Account> filterD1 = filterBuilder.Eq(m => m._id, txn.Dst);//dest FilterDefinition <Account> filterD2 = filterBuilder.Where(m => m.Txns.Contains(txn._id)); FilterDefinition <Account> filterD = filterBuilder.And(new FilterDefinition <Account>[] { filterD1, filterD2 }); var updateD = Builders <Account> .Update.Inc(m => m.Balance, -txn.Amt).Pull(m => m.Txns, txn._id); mongoDBService.DocumentUpdate(AccountsCollectionName, filterD, updateD); //删除事务文档 mongoDBService.Delete <TransactionDocument>(TransactionCollectionName, m => m._id == txn._id); }