SmartSql使用教程(3)——SmartSql中的事务,及AOP的使用
一、引言
经过两章的铺垫,我们现在对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 }
在这个类中,我实现了两次事务调用。在第一个方法中我们使用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