利用AOP實(shí)現(xiàn)SqlSugar自動(dòng)事務(wù)
本文實(shí)例為大家分享了如何利用AOP實(shí)現(xiàn)SqlSugar自動(dòng)事務(wù),供大家參考,具體內(nèi)容如下
先看一下效果,帶接口層的三層架構(gòu):
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; } }
假設(shè)GetStudentList方法里的mStudentDa.GetStudents和mValueService.FindAll不是查詢操作,而是更新操作,當(dāng)一個(gè)失敗另一個(gè)需要回滾,就需要在同一個(gè)事務(wù)里,當(dāng)一個(gè)出現(xiàn)異常就要回滾事務(wù)。
特性TransactionCallHandler就表明當(dāng)前方法需要開啟事務(wù),并且當(dāng)出現(xiàn)異常的時(shí)候回滾事務(wù),方法執(zhí)行完后提交事務(wù)。
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(); } }
對(duì)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, //默認(rèn)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("創(chuàng)建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("內(nèi)部錯(cuò)誤: SqlSugarClient已丟失."); } return id; } public static void BeginTran() { var instance=GetInstance(); //開啟事務(wù) if (!instance.IsBeginTran) { instance.SqlSugarClient.Ado.BeginTran(); instance.IsBeginTran = true; } } public static void CommitTran() { var id = GetId(); if (!_cache.ContainsKey(id)) throw new Exception("內(nèi)部錯(cuò)誤: 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("內(nèi)部錯(cuò)誤: 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("內(nèi)部錯(cuò)誤: SqlSugarClient已丟失."); _cache[id].TranCount++; } public static void TranCountMunisOne() { var id = GetId(); if (!_cache.ContainsKey(id)) throw new Exception("內(nèi)部錯(cuò)誤: SqlSugarClient已丟失."); _cache[id].TranCount--; } }
_cache保存SqlSugar實(shí)例,_threadLocal確保同一線程下取出的是同一個(gè)SqlSugar實(shí)例。
不知道SqlSugar判斷當(dāng)前實(shí)例是否已經(jīng)開啟事務(wù),所以又將SqlSugar包了一層。
public class SqlClient { public SqlSugarClient SqlSugarClient; public bool IsBeginTran = false; public int TranCount = 0; public SqlClient(SqlSugarClient sqlSugarClient) { this.SqlSugarClient = sqlSugarClient; } }
IsBeginTran標(biāo)識(shí)當(dāng)前SqlSugar實(shí)例是否已經(jīng)開啟事務(wù),TranCount是一個(gè)避免事務(wù)嵌套的計(jì)數(shù)器。
一開始的例子
[TransactionCallHandler] public IList<Student> GetStudentList(Hashtable paramsHash) { var list = mStudentDa.GetStudents(paramsHash); var value = mValueService.FindAll(); return list; }
TransactionCallHandler表明該方法要開啟事務(wù),但是如果mValueService.FindAll也標(biāo)識(shí)了TransactionCallHandler,又要開啟一次事務(wù)?所以用TranCount做一個(gè)計(jì)數(shù)。
使用Castle.DynamicProxy
要實(shí)現(xiàn)標(biāo)識(shí)了TransactionCallHandler的方法實(shí)現(xiàn)自動(dòng)事務(wù),使用Castle.DynamicProxy實(shí)現(xiàn)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就是要開啟事務(wù)的地方,after就是提交事務(wù)的地方
最后實(shí)現(xiàn)
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結(jié)合使用
創(chuàng)建代理的時(shí)候一個(gè)BL類就要一次操作
proxyGenerate.CreateClassProxy<MyClass>(t);
而且項(xiàng)目里BL類的實(shí)例化是交給IOC容器控制的,我用的是Autofac。當(dāng)然Autofac和Castle.DynamicProxy是可以結(jié)合使用的
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>(); } }
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
那些年,我還在學(xué)習(xí)C# 學(xué)習(xí)筆記續(xù)
那些年學(xué)習(xí)C#,就是對(duì)C#相關(guān)的一些知識(shí)有一個(gè)了解,等到要用時(shí)才不會(huì)找不到方向,比如說擴(kuò)展方法,開始時(shí)怎么覺得沒有用,后來了解到asp.net MVC,它可以用來擴(kuò)展Html類,比如做一個(gè)分頁的方法;所以對(duì)一門語言了解寬一些是沒有壞處的2012-03-03深入解析C#中的交錯(cuò)數(shù)組與隱式類型的數(shù)組
這篇文章主要介紹了深入解析C#中的交錯(cuò)數(shù)組與隱式類型的數(shù)組,隱式類型的數(shù)組通常與匿名類型以及對(duì)象初始值設(shè)定項(xiàng)和集合初始值設(shè)定項(xiàng)一起使用,需要的朋友可以參考下2016-01-01C#遞歸實(shí)現(xiàn)將一整數(shù)逆序后放入一數(shù)組中
這篇文章主要介紹了C#遞歸實(shí)現(xiàn)將一整數(shù)逆序后放入一數(shù)組中,是遞歸算法的一個(gè)簡單應(yīng)用,需要的朋友可以參考下2014-10-10C#打包部署并把.net framework框架打到安裝包的方法步驟
打包c(diǎn)#程序時(shí),有時(shí)需要添加.net framework組件到安裝包,本文就來介紹一下C#打包部署并把.net framework框架打到安裝包的方法步驟,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10