好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

利用AOP实现SqlSugar自动事务

本文实例为大家分享了如何利用AOP实现SqlSugar自动事务,供大家参考,具体内容如下

先看一下效果,带接口层的三层架构:

BL层:

?

public class StudentBL : IStudentService

   {

     private ILogger mLogger;

     private readonly IStudentDA mStudentDa;

     private readonly IValueService mValueService;

 

     public StudentService(IStudentDA studentDa,IValueService valueService)

     {

       mLogger = LogManager.GetCurrentClassLogger();

       mStudentDa = studentDa;

       mValueService = valueService;

 

     }

 

     [TransactionCallHandler]

     public IList<Student> GetStudentList(Hashtable paramsHash)

     {

       var list = mStudentDa.GetStudents(paramsHash);

       var value = mValueService.FindAll();

       return list;

     }

   }

假设GetStudentList方法里的mStudentDa.GetStudents和mValueService.FindAll不是查询操作,而是更新操作,当一个失败另一个需要回滚,就需要在同一个事务里,当一个出现异常就要回滚事务。

特性TransactionCallHandler就表明当前方法需要开启事务,并且当出现异常的时候回滚事务,方法执行完后提交事务。

DA层:

?

public class StudentDA : IStudentDA

   {

 

     private SqlSugarClient db;

     public StudentDA()

     {

       db = SugarManager.GetInstance().SqlSugarClient;

     }

     public IList<Student> GetStudents(Hashtable paramsHash)

     {

       return db.Queryable<Student>().AS( "T_Student" ).With(SqlWith.NoLock).ToList();

     }

   }

对SqlSugar做一下包装

 

?

public class SugarManager

   {

     private static ConcurrentDictionary< string ,SqlClient> _cache =

       new ConcurrentDictionary< string , SqlClient>();

     private static ThreadLocal< string > _threadLocal;

     private static readonly string _connStr = @"Data Source=localhost;port=3306;Initial Catalog=thy;user id=root;password=xxxxxx;Charset=utf8" ;

     static SugarManager()

     {

       _threadLocal = new ThreadLocal< string >();

     }

 

     private static SqlSugarClient CreatInstance()

     {

       SqlSugarClient client = new SqlSugarClient( new ConnectionConfig()

       {

         ConnectionString = _connStr, //必填

         DbType = DbType.MySql, //必填

         IsAutoCloseConnection = true , //默认false

         InitKeyType = InitKeyType.SystemTable

       });

       var key=Guid.NewGuid().ToString().Replace( "-" , "" );

       if (!_cache.ContainsKey(key))

       {

         _cache.TryAdd(key, new SqlClient(client));

         _threadLocal.Value = key;

         return client;

       }

       throw new Exception( "创建SqlSugarClient失败" );

     }

     public static SqlClient GetInstance()

     {

       var id= _threadLocal.Value;

       if ( string .IsNullOrEmpty(id)||!_cache.ContainsKey(id))

         return new SqlClient(CreatInstance());

       return _cache[id];

     }

 

 

     public static void Release()

     {

       try

       {

         var id = GetId();

         if (!_cache.ContainsKey(id))

           return ;

         Remove(id);

       }

       catch (Exception e)

       {

         throw e;

       }

     }

     private static bool Remove( string id)

     {

       if (!_cache.ContainsKey(id)) return false ;

 

       SqlClient client;

 

       int index = 0;

       bool result = false ;

       while (!(result = _cache.TryRemove(id, out client)))

       {

         index++;

         Thread.Sleep(20);

         if (index > 3) break ;

       }

       return result;

     }

     private static string GetId()

     {

       var id = _threadLocal.Value;

       if ( string .IsNullOrEmpty(id))

       {

         throw new Exception( "内部错误: SqlSugarClient已丢失." );

       }

       return id;

     }

 

     public static void BeginTran()

     {

       var instance=GetInstance();

       //开启事务

       if (!instance.IsBeginTran)

       {

         instance.SqlSugarClient.Ado.BeginTran();

         instance.IsBeginTran = true ;

       }

     }

 

     public static void CommitTran()

     {

       var id = GetId();

       if (!_cache.ContainsKey(id))

         throw new Exception( "内部错误: SqlSugarClient已丢失." );

       if (_cache[id].TranCount == 0)

       {

         _cache[id].SqlSugarClient.Ado.CommitTran();

         _cache[id].IsBeginTran = false ;

       }

     }

 

     public static void RollbackTran()

     {

       var id = GetId();

       if (!_cache.ContainsKey(id))

         throw new Exception( "内部错误: SqlSugarClient已丢失." );

       _cache[id].SqlSugarClient.Ado.RollbackTran();

       _cache[id].IsBeginTran = false ;

       _cache[id].TranCount = 0;

     }

 

     public static void TranCountAddOne()

     {

       var id = GetId();

       if (!_cache.ContainsKey(id))

         throw new Exception( "内部错误: SqlSugarClient已丢失." );

       _cache[id].TranCount++;

     }

     public static void TranCountMunisOne()

     {

       var id = GetId();

       if (!_cache.ContainsKey(id))

         throw new Exception( "内部错误: SqlSugarClient已丢失." );

       _cache[id].TranCount--;

     }

   }

_cache保存SqlSugar实例,_threadLocal确保同一线程下取出的是同一个SqlSugar实例。

不知道SqlSugar判断当前实例是否已经开启事务,所以又将SqlSugar包了一层。

?

public class SqlClient

   {

     public SqlSugarClient SqlSugarClient;

     public bool IsBeginTran = false ;

     public int TranCount = 0;

 

     public SqlClient(SqlSugarClient sqlSugarClient)

     {

       this .SqlSugarClient = sqlSugarClient;

     }

   }

IsBeginTran标识当前SqlSugar实例是否已经开启事务,TranCount是一个避免事务嵌套的计数器。

一开始的例子

?

[TransactionCallHandler]

      public IList<Student> GetStudentList(Hashtable paramsHash)

      {

        var list = mStudentDa.GetStudents(paramsHash);

        var value = mValueService.FindAll();

        return list;

      }

TransactionCallHandler表明该方法要开启事务,但是如果mValueService.FindAll也标识了TransactionCallHandler,又要开启一次事务?所以用TranCount做一个计数。

使用Castle.DynamicProxy

要实现标识了TransactionCallHandler的方法实现自动事务,使用Castle.DynamicProxy实现BL类的代理

Castle.DynamicProxy一般操作

 

?

public class MyClass : IMyClass

  {

    public void MyMethod()

    {

      Console.WriteLine( "My Mehod" );

    }

}

public class TestIntercept : IInterceptor

   {

     public void Intercept(IInvocation invocation)

     {

       Console.WriteLine( "before" );

       invocation.Proceed();

       Console.WriteLine( "after" );

     }

   }

 

  var proxyGenerate = new ProxyGenerator();

  TestIntercept t= new TestIntercept();

  var pg = proxyGenerate.CreateClassProxy<MyClass>(t);

  pg.MyMethod();

  //输出是

  //before

  //My Mehod

  //after

before就是要开启事务的地方,after就是提交事务的地方

最后实现

?

public class TransactionInterceptor : IInterceptor

   {

     private readonly ILogger logger;

     public TransactionInterceptor()

     {

       logger = LogManager.GetCurrentClassLogger();

     }

     public void Intercept(IInvocation invocation)

     {

       MethodInfo methodInfo = invocation.MethodInvocationTarget;

       if (methodInfo == null )

       {

         methodInfo = invocation.Method;

       }

 

       TransactionCallHandlerAttribute transaction =

         methodInfo.GetCustomAttributes<TransactionCallHandlerAttribute>( true ).FirstOrDefault();

       if (transaction != null )

       {

         SugarManager.BeginTran();

         try

         {

           SugarManager.TranCountAddOne();

           invocation.Proceed();

           SugarManager.TranCountMunisOne();

           SugarManager.CommitTran();

         }

         catch (Exception e)

         {

           SugarManager.RollbackTran();

           logger.Error(e);

           throw e;

         }

 

       }

       else

       {

         invocation.Proceed();

       }

     }

   }

   [AttributeUsage(AttributeTargets.Method, Inherited = true )]

   public class TransactionCallHandlerAttribute : Attribute

   {

     public TransactionCallHandlerAttribute()

     {

 

     }

   }

Autofac与Castle.DynamicProxy结合使用

创建代理的时候一个BL类就要一次操作

?

proxyGenerate.CreateClassProxy<MyClass>(t);

而且项目里BL类的实例化是交给IOC容器控制的,我用的是Autofac。当然Autofac和Castle.DynamicProxy是可以结合使用的

?

using System.Reflection;

using Autofac;

using Autofac.Extras.DynamicProxy;

using Module = Autofac.Module;

public class BusinessModule : Module

   {

     protected override void Load(ContainerBuilder builder)

     {

       var business = Assembly.Load( "FTY.Business" );

       builder.RegisterAssemblyTypes(business)

         .AsImplementedInterfaces().InterceptedBy( typeof (TransactionInterceptor)).EnableInterfaceInterceptors();

       builder.RegisterType<TransactionInterceptor>();

     }

   }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://HdhCmsTestcnblogs测试数据/jaycewu/archive/2017/10/25/7733114.html

dy("nrwz");

查看更多关于利用AOP实现SqlSugar自动事务的详细内容...

  阅读:49次