SmartSql = MyBatis + Cache(Memory | Redis) + R/W Splitting +Dynamic Repository + Diagnostics ...... ...
一、引言
經過兩章的鋪墊,我們現在對SmartSql已經有了一定的瞭解,那麼今天我們的主題是事務處理。事務處理是常用的一種特性,而SmartSql至少提供了兩種使用事務的方法。一種是通過Repository(動態倉儲)或者ITransaction的常規調用,一種是基於AOP提醒的動態代理方式。接下來我們一個個說。
上圖是這一章的項目結構,這次的結構略微有點複雜,我一一解釋。
項目結構分為3個部分,Api部分分成了3個.NetCore MVC項目,三個項目分別是常規調用;基於.NetCore原生DI的AOP調用;基於Autofac的AOP調用,AOP部分的區別隻是在DI的配置部分。
DomainService也就是業務邏輯層,這個沒什麼好說的。
Data Access部分是實體與動態倉儲,而在這一章中。我們的動態倉儲項目有一個小的變動。先放圖
通過圖片可以看到,原來我們放在Api項目中的Map和Config都放到了動態倉儲的項目。這個因為在當前項目中,我們有3個輸出項目。如果每個項目中都寫一套Maps就顯得很多此一舉。所以把它們統一的放到倉儲類庫里來,是一個很好的辦法(虎哥提供)。註:別忘記把文件設置成始終複製哦
二、 常規使用
用法寫在上面忽略了的DomainService中
1 using System; 2 using SmartSql.DbSession; 3 using SmartSqlSampleChapterThree.Entity; 4 using SmartSqlSampleChapterThree.Repository; 5 6 namespace SmartSqlSampleChapterThree.DomainService 7 { 8 public class NormalUserDomainService : IUserDomainService 9 { 10 private const string DEFAULT_AVATAR = "https://smartsql.net/logo.png"; 11 12 private readonly IUserRepository _userRepository; 13 private readonly IUserDetailRepository _userDetailRepository; 14 private readonly ITransaction _transaction; 15 16 public NormalUserDomainService(IUserRepository userRepository, IUserDetailRepository userDetailRepository, ITransaction transaction) 17 { 18 _userRepository = userRepository; 19 _userDetailRepository = userDetailRepository; 20 _transaction = transaction; 21 } 22 23 public User Register(string loginName, string password, string nickname) 24 { 25 try 26 { 27 _transaction.BeginTransaction(); 28 var user = new User 29 { 30 LoginName = loginName, 31 Password = password, 32 Status = 1, 33 CreateTime = DateTime.Now, 34 ModifiedTime = DateTime.Now 35 }; 36 37 user.Id = _userRepository.Insert(user); 38 39 _userDetailRepository.Insert(new UserDetail 40 { 41 UserId = user.Id, 42 Nickname = nickname, 43 Avatar = DEFAULT_AVATAR, 44 Sex = null, 45 CreateTime = DateTime.Now, 46 ModifiedTime = DateTime.Now 47 }); 48 49 _transaction.CommitTransaction(); 50 return user; 51 } 52 catch 53 { 54 _transaction.RollbackTransaction(); 55 throw; 56 } 57 } 58 59 // use transaction on repository's sql mapper 60 public User RegisterUseRepository(string loginName, string password, string nickname) 61 { 62 try 63 { 64 _userRepository.SqlMapper.BeginTransaction(); 65 66 var user = new User 67 { 68 LoginName = loginName, 69 Password = password, 70 Status = 1, 71 CreateTime = DateTime.Now, 72 ModifiedTime = DateTime.Now 73 }; 74 75 user.Id = _userRepository.Insert(user); 76 77 _userDetailRepository.Insert(new UserDetail 78 { 79 UserId = user.Id, 80 Nickname = nickname, 81 Avatar = DEFAULT_AVATAR, 82 Sex = null, 83 CreateTime = DateTime.Now, 84 ModifiedTime = DateTime.Now 85 }); 86 87 _userRepository.SqlMapper.CommitTransaction(); 88 return user; 89 } 90 catch 91 { 92 _userRepository.SqlMapper.RollbackTransaction(); 93 throw; 94 } 95 } 96 } 97 }NormalUserDomainService
在這個類中,我實現了兩次事務調用。在第一個方法中我們使用ITransaction介面提供的方法,調用了Begin-Commit-Rollback的事務過程。
第二個方法中,我直接使用了Repository.SqlMap.BeginTransaction(),這是因為IRepository包含了一個ISqlMap,而ISqlMap同時繼承了ITransaction。所以本質上這兩種方式是等價的。
三、AOP
1. Nuget依賴
SmartSql有一個獨立的Nuget包來支持AOP實現。名字就叫“SmartSql.AOP”
2. DomainService
使用了AOP後,我們的業務代碼就可以乾凈很多。只需要在方法前加上[Transaction]特性就可以了。只要方法體中拋出異常,事務即會回滾。
[Transaction] public User Register(string loginName, string password, string nickname) { var user = new User { LoginName = loginName, Password = password, Status = 1, CreateTime = DateTime.Now, ModifiedTime = DateTime.Now }; user.Id = _userRepository.Insert(user); _userDetailRepository.Insert(new UserDetail { UserId = user.Id, Nickname = nickname, Avatar = DEFAULT_AVATAR, Sex = null, CreateTime = DateTime.Now, ModifiedTime = DateTime.Now }); return user; }
3. 原生配置
在Startup中稍稍修改一下ConfigureServices即可。
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(); /// 服務註冊 Begin /// 服務註冊 End return services.BuildAspectInjectorProvider(); }
看一下上面代碼你會發現,只需要為ConfigureServices方法加一個IServiceProvider返回值。併在方法最後加一句return就可以了。
4. Autofac配置
在Autofac中與原生相比,略微有一些不同。
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(); /// 服務註冊 Begin /// 服務註冊 End // autofac var builder = new ContainerBuilder(); builder.RegisterDynamicProxy(config => { config.Interceptors .AddTyped<TransactionAttribute>(Predicates.ForNameSpace("SmartSqlSampleChapterThree.DomainService")); }); builder.Populate(services); var container = builder.Build(); return new AutofacServiceProvider(container); }
我在項目中很少使用Autofac,所以對它的特性也不是很瞭解。只是按照文檔做了最簡單的實現,這裡還要特別感謝交流群的小伙伴(QQ群號:604762592)。是群里的一個小伙伴在使用Autofac的時候分享了他的使用方式。
這裡在原生的基礎上,創建一個Autofac容器構建器,併在構建器中註冊一個動態代理。然後在攔截器中加上TransactionAttribute就可以了。
三、結語
以上就是SmartSql中事務處理的一些方法,希望可以幫助到你。
下期預告:TypeHandler類型處理器使用講解 And 如何自定義TypeHandler