前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ADO.NET事务封装

ADO.NET事务封装

作者头像
code2roc
发布2023-07-19 14:41:06
2050
发布2023-07-19 14:41:06
举报

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

代码语言:javascript
复制
   public bool ExecuteTransition(Action TransitionAction, out string ExceptionStr)

外部传入的数据库操作都使用委托统一打包,内部进行事务操作。我们首先需要明白的是,数据库事务操作在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 代码

代码语言:javascript
复制
 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);
            }
        }

对外事物执行方法

代码语言:javascript
复制
    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;

        }

完整模块代码地址:

FastExecutorCore: 基于NetCore3.1开发后台管理系统框架(个人学习) - Gitee.com

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-07-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档