C# 中的自定义业务事务





2.00/5 (3投票s)
2007年11月19日
2分钟阅读

30209

296
一篇基于 LLBLGen Pro 实现自定义业务事务类的文章。
引言
在每个项目中,我们都需要一个业务事务类来帮助我们控制业务流程。这个类应该能够处理嵌套事务。我编写了一个名为“BusinessTransaction”的类,并希望与所有在处理嵌套事务时遇到问题的人分享它。
背景
在许多情况下,我们有一些服务/门面/管理器,它们处理数据容器并将它们保存到数据库中。有时这些服务也会相互调用,在这种情况下,如果在内部服务中发生任何异常,则异常将在 2 层事务中抛出,并且两者都应该回滚。
例如,在像这样的算法中:
public void X() { try { transaction.Start(); console.WriteLine("X"); transaction.Commit(); } catch(Exception ex) { transaction.Rollback(); throw ex; } } public void Y() { try { transaction.Start(); console.WriteLine("Y"); transaction.Commit(); } catch(Exception ex) { transaction.Rollback(); throw ex; } } public void Z() { try { transaction.Start(); X(); Y(); transaction.Commit(); } catch(Exception ex) { transaction.Rollback(); throw ex; } }
我们可能会遇到以下情况:
1- 异常发生在 X 事务之间:X 和 Z 应该回滚。
2- 异常发生在 X 提交之后且 Y 事务之间:X、Y 和 Z 应该回滚。
3- 异常发生在 X 提交之后且 Y 事务之间,但 Y 没有抛出它:仅 Y 应该回滚,X 和 Z 必须提交。
4- 异常发生在 Y 提交之后:X、Y 和 Z 应该回滚。
因此,我尝试在我的代码中处理所有这些情况并对其进行了测试;它有效!
我总是使用 LLBLGen Pro. 作为 ORM,当然你也可以在我的代码中看到它,但如果你不熟悉它,也不用担心,相关的代码很容易理解!
使用代码
我使用堆栈来处理嵌套事务。在每个 Start() 方法中,相关的事务标识符都会被推入其中,只有当堆栈为空时,才意味着不存在外部事务,所以我才启动一个真实的事务。
/// <summary> /// starts a new Transaction or an inner Transaction /// </summary> /// <param name="isolationLevel"></param> public void Start(IsolationLevel isolationLevel) { string startMethodName = GetSavePoint(); int transactionID = tarnsactionIDToInfoMap.Count + 1; if (transactionStack.Count == 0) { adapter.StartTransaction(isolationLevel, "1"); tarnsactionIDToInfoMap.Clear(); } else { adapter.SaveTransaction(transactionID.ToString()); } tarnsactionIDToInfoMap.Add(transactionID, startMethodName); transactionStack.Push(transactionID); }
当调用 commit() 或 rollback() 时,会弹出一个事务,再次如果堆栈变为空,则意味着该事务是真实的,必须回滚或提交。
/// <summary> /// Commits the mosty inner Transaction /// </summary> public void Commit() { if (transactionStack.Count == 0) { throw new FatalException("Error in transaction Handling. Commit on empty stack", true); } string commitMethodName = GetSavePoint(); string srartMethodName = tarnsactionIDToInfoMap[(int)(transactionStack.Pop())].ToString(); if (!commitMethodName.Equals(srartMethodName)) { LogManager.Instance.WriteWarning("Unmatched transaction. " + "The Start Transaction was called from " + srartMethodName + " but it was commited in " + commitMethodName); } if (transactionStack.Count == 0) { adapter.Commit(); } } /// <summary> /// Rolls back the mosty inner Transaction /// </summary> public void Rollback() { if (transactionStack.Count == 0) { throw new FatalException("Error in transaction Handling. Rollback on empty stack", true); } int transactionID = (int)(transactionStack.Pop()); string rollbackMethodName = GetSavePoint(); string startMethodName = tarnsactionIDToInfoMap[transactionID].ToString(); if (!rollbackMethodName.Equals(startMethodName)) { LogManager.Instance.WriteWarning("Unmatched transaction. " + "The Start Transaction was called from " + startMethodName + " but it was rolled back in " + rollbackMethodName); } if (transactionStack.Count == 0) { adapter.Rollback(); } else { adapter.Rollback(transactionID.ToString()); } }我希望这个类对您有所帮助!