C#:数据库事务统一管理的解决方案

c#中常规事务的操作需要每次都打开链接、开启事务、执行语句、提交或回滚事务,在业务层或者数据访问层中每次都这样写会非常繁琐,

在最近遇到一个项目中需要实现类似于EntityFrameWork或者Ibatis.net中的事务管理,既将分散的事务统一管理在一次数据访问会话中:

例如 EntityFramework中管理事务的方式:

            using (MyDbContext context = new MyDbContext())
            {
                context.Students.Add(entity1);
                context.Students.Add(entity2);
                context.SaveChanges();
            }

又例如 Ibatis.net中的事务管理方式:

            DaoManager.BeginTransaction();
            try
            {
                ...
...
... DaoManager.CommitTransaction(); }
catch (Exception ex) { DaoManager.RollBackTransaction(); }

很多orm都实现了类似的统一管理事务功能。虽然再自己写一个也是重复造*,但是最近项目要用的是可以直接写sql的那种,    所以就自己实现了一个简陋版

实现的思路和方式

既然要统一管理事务,那么每次会话中的连接对象、事务对象就要保持一致; 所以使用一个上下文类来管理每次会话:

DataContext类:

public partial class DataContext
        {
            //数据访问对象
            private DataAccess _da;

            public DataContext() { _da = new DataAccess(); }
            //开启事务
            public IDbTransaction BeginTransaction()
            {
                return _da.BeginTransaction();
            }
            //是否不可用
            public bool IsEnabled { get; set; }
            //提交事务
            public void Commit()
            {
                _da.Commit();
            }
            //回滚事务
            public void RollBack()
            {
                _da.RollBack();
            }
        }

上下文类持有一个数据访问的对象,通过这个对象来进行统一访问事务的开启、提交和回滚

DataAccess类:

        public delegate void ExcuteNonQuery(string sql, object param);
        public class DataAccess
        {
            private IDbConnection conn;

            private IDbTransaction trans;

            private Dictionary<string, object> _DalDic;
            public DataAccess()
            {
                conn = new SqlConnection("YOUR DBCONNECTION STRING");
            }
            public IDbTransaction BeginTransaction()
            {
                if (conn.State != ConnectionState.Open)
                    conn.Open();
                 trans= conn.BeginTransaction();
                return trans;
            }

            public void Commit()
            {
                if (trans != null)
                    trans.Commit();
            }

            public void RollBack()
            {
                if (trans != null)
                    trans.Rollback();
            }

            public IDal<T> GetDal<T>() where T:class
            {
                lock (this)
                {
                    Type type = typeof(T);
                    IDal<T> Dal = null;
                    if (_DalDic == null)
                        _DalDic = new Dictionary<string, object>();
                    if (_DalDic.ContainsKey(type.Name))
                        Dal = _DalDic[type.Name] as IDal<T>;
                    else
                    {
                        Dal = DaoFactory.GetDal<T>(type);
                        Dal.conn = conn;
                        Dal.excuteNonQuery = ExcuteNonQuery;
                    }
                    return Dal;
                }
            }

            private void ExcuteNonQuery(string sql,object t)
            {
                conn.Execute(sql, t, trans);
            }
            
        }

访问类管理了链接对象和事务对象。

然后通过GetDal()方法来获取一个实际的Dao层对象,例如下面的studetnDao 、TeacherDao等等。

同时,使用一个委托ExcuteNonQuery(string sql, object param) 将实际的curd操作方法赋值给dao对象中的curd方法:Dal.excuteNonQuery = ExcuteNonQuery;

实际的curd操作也就是上面的ExcuteNonQuery方法,它使用了本对象DataAccess类中的事务对象, 这样就实现了统一事务对象。

获取dal对象使用了简单工厂的设计模式:

DaoFactory类:

public class DaoFactory
        {
            public static IDal<T> GetDal<T>(Type type)
            {
                IDal<T> dao = null ;
                if (type == new UnitInfo().GetType())
                {
                    dao = new UnitInfoDao() as IDal<T>;
                }
                else if (type == new StudentInfo().GetType())
                {
                    dao = new StudentDao() as IDal<T>;
                }
          else if......
......
......
......
return dao; } }

接下来就是dal层了,里面就是最基础的CRUD:

Dal层的各个对象:

        public interface IDal<TDao>
        {
            IDbConnection conn { get; set; }
            void Edit(TDao t);

            void Insert(TDao t);

            IQueryable<TDao> Query(string sql, object paramse);

            void Delete(TDao t);

            ExcuteNonQuery excuteNonQuery { get; set; }
        }

因为要操作实体,所以dal层用了泛型接口,dal层中有一个上面说的委托对象excuteNonQuery。

dal的实现类:(这里作为示例, 只实现了update方法)

public class TeacherDao : BaseDao, IDal<TeacherInfo>
        {
            public IDbConnection conn
            {
                get { return base.Conn; }
                set { base.Conn = value; }
            }

            public ExcuteNonQuery excuteNonQuery { get; set; }

            public void Delete(TeacherInfo t)
            {
                throw new NotImplementedException();
            }

            public void Edit(TeacherInfo t)
            {
                string sql = "update TeacherInfo Set Name=@Name where ID=@ID";
                if (excuteNonQuery != null)
                    excuteNonQuery(sql, t);
                else
                {
                    //你的基本curd实现方法
                    //Conn.Query<StudentInfo>(sql, t);
                }
            }

            public void Insert(TeacherInfo t)
            {
                throw new NotImplementedException();
            }

            public IQueryable<TeacherInfo> Query(string sql, object paramse)
            {
                throw new NotImplementedException();
            }
        }

        public class StudentDao : BaseDao, IDal<StudentInfo>
        {
            public IDbConnection conn
            {
                get { return base.Conn; }
                set { base.Conn = value; }
            }

            public ExcuteNonQuery excuteNonQuery { get; set; }

            public void Delete(StudentInfo t)
            {
                throw new NotImplementedException();
            }

            public void Edit(StudentInfo t)
            {
                string sql = "update StudentInfo Set Name=@Name where ID=@ID";
                if (excuteNonQuery != null)
                    excuteNonQuery(sql, t);
                else
                {
                    //你的基本crud实现方法
                    //Conn.Query<StudentInfo>(sql, t);
                }
            }

            public void Insert(StudentInfo t)
            {
                throw new NotImplementedException();
            }

            public IQueryable<StudentInfo> Query(string sql, object paramse)
            {
                throw new NotImplementedException();
            }
        }

 这里就用到了DataAccess类中赋值给dao对象的委托类型。方式就是: 如果有委托,那就执行委托的方法(带有事务的方法),否则的话,就是执行上面注释掉的自己实现的普通的不带事务的crud方法。

 

刚才的DataContext类是分部类, 因为这里面还要加上获取各个dao对象的get属性:例如这里加上了获取StudentDao对象和TeacherDao对象:

DataContext分布类中dao对象的获取:

        public partial class DataContext
        {
            public IDal<TeacherInfo> TeacherInfoDao
            {
                get { return _da.GetDal<TeacherInfo>(); }
            }

            public IDal<StudentInfo> StudentInfoDao
            {
                get { return _da.GetDal<StudentInfo>(); }
            }
        }

 

至此的话事务统一管理已经实现了,看一下业务层中的使用:

调用:

         public void Test1()
        {
            var context = new DataContext();
            context.BeginTransaction();
            try
            {
                context.StudentInfoDao.Edit(new StudentInfo() { Name = "张三", ID = "123" });
                context.TeacherInfoDao.Edit(new TeacherInfo() { Name = "陈老师", ID = "234" });
                context.Commit();
            }
            catch
            {
                context.RollBack();
            }
        }

 

整个实现的总体思路,就是通过上下文和访问类统一管理dao对象, 使得dao对象如果有带事务的操作方法,那么就执行这个方法; 否则dao对象就执行普通的不带事务的方法。

 



C#:数据库事务统一管理的解决方案

上一篇:【模型推理】T4 上商汤 OpenPPL vs TensorRT7 vs TensorRT8 测评


下一篇:pytorch 网络模型可视化(七):PlotNeuralNet