• 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]特性就可以了。只要方法体中抛出异常,事务即会回滚。另外需要注意的地方是,AOP方法是需要用上virtual虚方法标识的。

            [Transaction]
            public virtual 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

  • 相关阅读:
    c# 进制
    java生成验证码
    java基础练习题
    java九九乘法表
    java list集合练习
    深入理解Java的接口和抽象类
    java 接口 练习
    java泛型详解
    Java 继承 小练习
    Java单例模式深入详解
  • 原文地址:https://www.cnblogs.com/noahji/p/11040274.html
Copyright © 2020-2023  润新知