在數據庫工具類編寫的過程中,對事務的處理操作想避免各個原子操作的事務對象賦值重復操作,想對外暴露的方法為如下形式
外部傳入的數據庫操作都使用委托統一打包,內部進行事務操作。我們首先需要明白的是,數據庫事務操作在ADO.NET的編碼中的體現是,DbConnection為同一個,DbCommand的Transaction為同一個。
首先我們需要識每一個數據庫操作的上下文,是否在TransitionAction這個委托中,為了簡單明了,在執行TransitionAction時開啟一個Task,取得當前線程的ThreadID作為這個事務委托的唯一標識,並生成一個DbTransaction放入一個TransactionDic中,在SqlHelper執行類中執行SQL語句創建Connection時,取得當前的ThreadID去TransactionDic中查找,如果有對應的Transition則說明該SQL語句的執行是在一個事務中,Connection直接取Transition的數據庫連接,並給DbCommand的Transition對象賦值
這個解決方案對於TransitionAction中執行方法類中的數據庫操作或其他組合操作也是可行的,但是對於嵌套事務還需要進一步改進。
比如我封裝好一個框架的工作流方法MethodA,自帶事物執行,但是需要與業務更新方法MethodB進行事物組合操作,上述方案並不能滿足要求,需要我們進行改進,判斷當前的事物TransitionAction是否是嵌套事務,即TransitionActionB實際是打包在TransitionActionA中的。在TransitionAction的DbTransaction添加的過程中,我們需要取到Task之外的ThreadID,這里稱作為RootThreadID,同時維護一個ConcurrentDictionary<string, List<string>> TransitionIDMapDic,用於維護RootThreadID與嵌套事務的ThreadID的關系,在創建Task時就可以判斷當前的ThreadID是否在TransactionDic,存在就是嵌套事務,需要將當前的TransitionAction合並到Root事物中
TransactionManage 代碼
對外事物執行方法
public bool ExecuteTransition(Action TransitionAction, out string ExceptionStr) { bool IsSuccess = true; ExceptionStr = string.Empty; string RootThreadID = Thread.CurrentThread.ManagedThreadId.ToString(); var TrabsitionTask = new Task<LocalTransactionResult>(() => { string TransitionID = Thread.CurrentThread.ManagedThreadId.ToString(); LocalTransactionResult Result = new LocalTransactionResult(); if (!TransactionManage.ContainsTransition(RootThreadID)) { using (DbConnection connection = DBExecute.CreateConnection(ConnectionString)) { connection.Open(); DbTransaction Transaction = connection.BeginTransaction(); TransactionManage.AddTransition(TransitionID, RootThreadID, Transaction, TransitionAction); try { TransactionManage.GetTransition(TransitionID).Execute(); Transaction.Commit(); } catch (System.Exception e) { Result.ExecuteStatus = false; Result.ExceptionMessage = e.Message; Transaction.Rollback(); } finally { Transaction.Dispose(); connection.Close(); connection.Dispose(); Transaction = null; TransactionManage.RemoveTransition(TransitionID); } return Result; } } else { //當前是嵌套事務,不執行,由根事務統一執行 TransactionManage.ContactTransition(TransitionID, RootThreadID, TransitionAction); Result.ExecuteStatus = true; Result.ExceptionMessage = string.Empty; return Result; } }); TrabsitionTask.Start(); TrabsitionTask.Wait(); IsSuccess = TrabsitionTask.Result.ExecuteStatus; ExceptionStr = TrabsitionTask.Result.ExceptionMessage; return IsSuccess; }
完整模塊代碼地址:https://gitee.com/grassprogramming/FastExecutorCore/tree/master/code/FastCore/FastCore/FastORM
注:個人感覺使用線程的方式雖然很方便但是實際使用過程中多線程可能會出現問題,后續會對執行類進行上下文對象的綁定改造