ADO.NET事务封装

在数据库工具类编写的过程中,对事务的处理操作想避免各个原子操作的事务对象赋值重复操作,想对外暴露的方法为如下形式

   public bool ExecuteTransition(Action TransitionAction, out string ExceptionStr)

外部传入的数据库操作都使用委托统一打包,内部进行事务操作。我们首先需要明白的是,数据库事务操作在ADO.NET的编码中的体现是,DbConnection为同一个,DbCommand的Transaction为同一个。

ADO.NET事务封装ADO.NET事务封装

首先我们需要识每一个数据库操作的上下文,是否在TransitionAction这个委托中,为了简单明了,在执行TransitionAction时开启一个Task,取得当前线程的ThreadID作为这个事务委托的唯一标识,并生成一个DbTransaction放入一个TransactionDic中,在SqlHelper执行类中执行SQL语句创建Connection时,取得当前的ThreadID去TransactionDic中查找,如果有对应的Transition则说明该SQL语句的执行是在一个事务中,Connection直接取Transition的数据库连接,并给DbCommand的Transition对象赋值

ADO.NET事务封装ADO.NET事务封装

这个解决方案对于TransitionAction中执行方法类中的数据库操作或其他组合操作也是可行的,但是对于嵌套事务还需要进一步改进。

比如我封装好一个框架的工作流方法MethodA,自带事物执行,但是需要与业务更新方法MethodB进行事物组合操作,上述方案并不能满足要求,需要我们进行改进,判断当前的事物TransitionAction是否是嵌套事务,即TransitionActionB实际是打包在TransitionActionA中的。在TransitionAction的DbTransaction添加的过程中,我们需要取到Task之外的ThreadID,这里称作为RootThreadID,同时维护一个ConcurrentDictionary<string, List<string>> TransitionIDMapDic,用于维护RootThreadID与嵌套事务的ThreadID的关系,在创建Task时就可以判断当前的ThreadID是否在TransactionDic,存在就是嵌套事务,需要将当前的TransitionAction合并到Root事物中

ADO.NET事务封装ADO.NET事务封装

TransactionManage 代码

 public class TransactionManage
{
private static ConcurrentDictionary<string, LocalTransaction> TransactionDic = new ConcurrentDictionary<string, LocalTransaction>();
private static ConcurrentDictionary<string, List<string>> TransitionIDMapDic = new ConcurrentDictionary<string, List<string>>();
public static void AddTransition(string TransitionID,string RootThreadID, DbTransaction Transition,Action TransitionAction)
{
LocalTransaction LT = new LocalTransaction();
LT.RootThreadID = RootThreadID;
LT.TransitionID = TransitionID;
LT.Transition = Transition;
//执行列表增加Action
LT.AddTransitionAction(TransitionAction);
TransactionDic.TryAdd(TransitionID, LT);
//增加事务根线程ID与嵌套事务相关事务ID
TransitionIDMapDic.TryAdd(RootThreadID, new List<string>() { TransitionID }); } public static void ContactTransition(string TransitionID, string RootThreadID,Action TransitionAction)
{
LocalTransaction LT = TransactionDic[RootThreadID];
if (!TransactionDic.ContainsKey(LT.RootThreadID))
{
LT.TransitionID = TransitionID;
//执行列表增加Action
LT.AddTransitionAction(TransitionAction);
TransactionDic.TryAdd(TransitionID, LT);
//增加事务根线程ID与嵌套事务相关事务ID
List<string> TransitionIDS = TransitionIDMapDic[LT.RootThreadID];
TransitionIDS.Add(TransitionID);
TransitionIDMapDic[LT.RootThreadID] = TransitionIDS;
}
else
{
ContactTransition(TransitionID, LT.RootThreadID, TransitionAction);
}
} public static string GetRootID(string TransitionID)
{
LocalTransaction LT = TransactionDic[TransitionID];
if (!TransactionDic.ContainsKey(LT.RootThreadID))
{
return LT.RootThreadID;
}
else
{
return GetRootID(LT.RootThreadID);
}
} public static LocalTransaction GetTransition(string TransitionID)
{
LocalTransaction LT = null;
TransactionDic.TryGetValue(TransitionID, out LT);
return LT;
}
public static bool ContainsTransition(string TransitionID)
{
return TransactionDic.ContainsKey(TransitionID);
}
public static void RemoveTransition(string TransitionID)
{
string RootID = GetRootID(TransitionID);
List<string> TransitionIDList = null;
TransitionIDMapDic.TryRemove(RootID, out TransitionIDList);
foreach (string TransitionIDItem in TransitionIDList)
{
LocalTransaction LT = null;
TransactionDic.TryRemove(TransitionIDItem, out LT);
}
}

对外事物执行方法

   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

注:个人感觉使用线程的方式虽然很方便但是实际使用过程中多线程可能会出现问题,后续会对执行类进行上下文对象的绑定改造

上一篇:六、.net core (.NET 6)程序部署到Docker上


下一篇:ADO执行事务