利用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>(); } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。