当前位置: 移动技术网 > IT编程>开发语言>c# > 利用AOP实现SqlSugar自动事务

利用AOP实现SqlSugar自动事务

2019年07月18日  | 移动技术网IT编程  | 我要评论

本文实例为大家分享了如何利用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>();
    }
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网