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 }
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

猜你喜欢

转载自www.cnblogs.com/noahji/p/11040274.html