利用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)前方法需要開(kāi)啟事務(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();
//開(kāi)啟事務(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)開(kāi)啟事務(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)開(kāi)啟事務(wù),TranCount是一個(gè)避免事務(wù)嵌套的計(jì)數(shù)器。
一開(kāi)始的例子
[TransactionCallHandler]
public IList<Student> GetStudentList(Hashtable paramsHash)
{
var list = mStudentDa.GetStudents(paramsHash);
var value = mValueService.FindAll();
return list;
}
TransactionCallHandler表明該方法要開(kāi)啟事務(wù),但是如果mValueService.FindAll也標(biāo)識(shí)了TransactionCallHandler,又要開(kāi)啟一次事務(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就是要開(kāi)啟事務(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>();
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#連接SQL?Sever數(shù)據(jù)庫(kù)與數(shù)據(jù)查詢實(shí)例之?dāng)?shù)據(jù)倉(cāng)庫(kù)詳解
最近的工作遇到了連接查詢,特在此記錄,以免日后以往,下面這篇文章主要給大家介紹了關(guān)于C#連接SQL?Sever數(shù)據(jù)庫(kù)與數(shù)據(jù)查詢實(shí)例之?dāng)?shù)據(jù)倉(cāng)庫(kù)的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
VisualStudio2019安裝C#環(huán)境的實(shí)現(xiàn)方法
這篇文章主要介紹了VisualStudio2019安裝C#環(huán)境的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
C#構(gòu)造函數(shù)在基類和父類中的執(zhí)行順序
這篇文章介紹了C#構(gòu)造函數(shù)在基類和父類中的執(zhí)行順序,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04
C#獲取文件名和文件路徑的兩種實(shí)現(xiàn)方式
這篇文章主要介紹了C#獲取文件名和文件路徑的兩種實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
Visual Studio連接unity編輯器的實(shí)現(xiàn)步驟
unity編輯器中打開(kāi)C#腳本的時(shí)候發(fā)現(xiàn)Visual Studio沒(méi)有連接unity編輯器,本文主要介紹了Visual Studio連接unity編輯器的實(shí)現(xiàn)步驟,感興趣的可以了解一下2023-11-11
C#實(shí)現(xiàn)只運(yùn)行單個(gè)實(shí)例應(yīng)用程序的方法(使用VB.Net的IsSingleInstance)
這篇文章主要介紹了C#實(shí)現(xiàn)只運(yùn)行單個(gè)實(shí)例應(yīng)用程序的方法,本文使用的是VB.Net的IsSingleInstance方法實(shí)現(xiàn),優(yōu)于Mutex 和 Process 這兩種只運(yùn)行單個(gè)應(yīng)用程序?qū)嵗姆椒?需要的朋友可以參考下2014-07-07

