欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SmartSql使用教程(3)——SmartSql中的事务,及AOP的使用

程序员文章站 2022-03-20 13:24:35
SmartSql = MyBatis + Cache(Memory | Redis) + R/W Splitting +Dynamic Repository + Diagnostics ...... ......

一、引言

  经过两章的铺垫,我们现在对smartsql已经有了一定的了解,那么今天我们的主题是事务处理。事务处理是常用的一种特性,而smartsql至少提供了两种使用事务的方法。一种是通过repository(动态仓储)或者itransaction的常规调用,一种是基于aop提醒的动态代理方式。接下来我们一个个说。

  SmartSql使用教程(3)——SmartSql中的事务,及AOP的使用

  上图是这一章的项目结构,这次的结构略微有点复杂,我一一解释。

  项目结构分为3个部分,api部分分成了3个.netcore mvc项目,三个项目分别是常规调用;基于.netcore原生di的aop调用;基于autofac的aop调用,aop部分的区别只是在di的配置部分。

  domainservice也就是业务逻辑层,这个没什么好说的。

  data access部分是实体与动态仓储,而在这一章中。我们的动态仓储项目有一个小的变动。先放图

  SmartSql使用教程(3)——SmartSql中的事务,及AOP的使用

  通过图片可以看到,原来我们放在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