通過兩章的鋪墊,咱們如今對SmartSql已經有了必定的瞭解,那麼今天咱們的主題是事務處理。事務處理是經常使用的一種特性,而SmartSql至少提供了兩種使用事務的方法。一種是經過Repository(動態倉儲)或者ITransaction的常規調用,一種是基於AOP提醒的動態代理方式。接下來咱們一個個說。git
上圖是這一章的項目結構,此次的結構略微有點複雜,我一一解釋。github
項目結構分爲3個部分,Api部分分紅了3個.NetCore MVC項目,三個項目分別是常規調用;基於.NetCore原生DI的AOP調用;基於Autofac的AOP調用,AOP部分的區別只是在DI的配置部分。sql
DomainService也就是業務邏輯層,這個沒什麼好說的。app
Data Access部分是實體與動態倉儲,而在這一章中。咱們的動態倉儲項目有一個小的變更。先放圖ide
經過圖片能夠看到,原來咱們放在Api項目中的Map和Config都放到了動態倉儲的項目。這個由於在當前項目中,咱們有3個輸出項目。若是每一個項目中都寫一套Maps就顯得不少此一舉。因此把它們統一的放到倉儲類庫裏來,是一個很好的辦法(虎哥提供)。注:別忘記把文件設置成始終複製哦ui
用法寫在上面忽略了的DomainService中spa
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 }
在這個類中,我實現了兩次事務調用。在第一個方法中咱們使用ITransaction接口提供的方法,調用了Begin-Commit-Rollback的事務過程。.net
第二個方法中,我直接使用了Repository.SqlMap.BeginTransaction(),這是由於IRepository包含了一個ISqlMap,而ISqlMap同時繼承了ITransaction。因此本質上這兩種方式是等價的。代理
SmartSql有一個獨立的Nuget包來支持AOP實現。名字就叫「SmartSql.AOP」code
使用了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; }
在Startup中稍稍修改一下ConfigureServices便可。
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(); /// 服務註冊 Begin /// 服務註冊 End return services.BuildAspectInjectorProvider(); }
看一下上面代碼你會發現,只須要爲ConfigureServices方法加一個IServiceProvider返回值。並在方法最後加一句return就能夠了。
在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中事務處理的一些方法,但願能夠幫助到你。