一、引言

  经过两章的铺垫,我们现在对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中

 using System;
using SmartSql.DbSession;
using SmartSqlSampleChapterThree.Entity;
using SmartSqlSampleChapterThree.Repository; namespace SmartSqlSampleChapterThree.DomainService
{
public class NormalUserDomainService : IUserDomainService
{
private const string DEFAULT_AVATAR = "https://smartsql.net/logo.png"; private readonly IUserRepository _userRepository;
private readonly IUserDetailRepository _userDetailRepository;
private readonly ITransaction _transaction; public NormalUserDomainService(IUserRepository userRepository, IUserDetailRepository userDetailRepository, ITransaction transaction)
{
_userRepository = userRepository;
_userDetailRepository = userDetailRepository;
_transaction = transaction;
} public User Register(string loginName, string password, string nickname)
{
try
{
_transaction.BeginTransaction();
var user = new User
{
LoginName = loginName,
Password = password,
Status = ,
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
}); _transaction.CommitTransaction();
return user;
}
catch
{
_transaction.RollbackTransaction();
throw;
}
} // use transaction on repository's sql mapper
public User RegisterUseRepository(string loginName, string password, string nickname)
{
try
{
_userRepository.SqlMapper.BeginTransaction(); var user = new User
{
LoginName = loginName,
Password = password,
Status = ,
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
}); _userRepository.SqlMapper.CommitTransaction();
return user;
}
catch
{
_userRepository.SqlMapper.RollbackTransaction();
throw;
}
}
}
}

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 = , 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

SmartSql使用教程(3)——SmartSql中的事务,及AOP的使用的更多相关文章

  1. SmartSql使用教程(2)——使用动态代理实现CURD

    一.引言 接着上一篇的教程,本章我们继续讲SmartSql.今天的主题是动态仓储. 老规矩,先上一个项目结构 从第二章开始.我们将原来的单一项目做了一个分离.方便之后的更新. 在这个结构中.原本上一章 ...

  2. SmartSql使用教程(1)——初探,建立一个简单的CURD接口服务

    一.引言 最近SmartSql被正式引入到了NCC,借着这个契机写一个使用教程系列 二.SmartSql简介[摘自官方文档] 1. SmartSql是什么? SmartSql = MyBatis + ...

  3. Entity Framework入门教程(19)---EF中使用事务

    EF中使用事务 这节介绍EF6中事务的使用.EF core中事务的使用方式和EF6中一模一样. 1.EF中的默认的事务 默认情况下,当我们执行一个SaveChanges()方法时就会新建了一个事务,然 ...

  4. SQL Server中的事务日志管理(9/9):监控事务日志

    当一切正常时,没有必要特别留意什么是事务日志,它是如何工作的.你只要确保每个数据库都有正确的备份.当出现问题时,事务日志的理解对于采取修正操作是重要的,尤其在需要紧急恢复数据库到指定点时.这系列文章会 ...

  5. Spring中@Transactional事务回滚

    转载: Spring中@Transactional事务回滚 一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部 ...

  6. 【MySQL】我这样分析MySQL中的事务,面试官对我刮目相看!!

    写在前面 相信大部分小伙伴在面试过程中,只会针对面试官提出的表面问题来进行回答.其实不然,面试官问的每一个问题都是经过深思熟虑的,面试的时间相对来说也是短暂的,面试官不可能在很短的时间内就对你非常了解 ...

  7. Microsoft SQL Server中的事务与并发详解

    本篇索引: 1.事务 2.锁定和阻塞 3.隔离级别 4.死锁 一.事务 1.1 事务的概念 事务是作为单个工作单元而执行的一系列操作,比如查询和修改数据等. 事务是数据库并发控制的基本单位,一条或者一 ...

  8. Redis系列之key操作命令与Redis中的事务详解(六)

    序言 本篇主要目的有二: 1.展示所有数据类型中key的所有操作命令,以供大家学习,查阅,更深入的挖掘redis潜力. 2.掌握redis中的事务,让你的数据完整性一致性拥有更优的保障. redis命 ...

  9. SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因

    原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中 ...

随机推荐

  1. caffe学习--cifar10学习-ubuntu16.04-gtx650tiboost--1g--02

    caffe学习--cifar10学习-ubuntu16.04-gtx650tiboost--1g--02 训练网络: caffe train -solver examples/cifar10/cifa ...

  2. ecshop 国付宝支付接口

    function get_code($order, $payment){ $version = '2.2'; $charset = '1'; $language = '1'; $signType = ...

  3. 按照eslint 规范写代码 [eslint] 'flag' is assigned to itself. (no-self-assign)

    按照eslint 规范写代码 [eslint] 'flag' is assigned to itself. (no-self-assign)

  4. Windows消息、绘图与多线程

    有一个项目,一旦点下按钮后,用死循环不停的读数据,读出后立刻用可视化的方法显示.如果不采用多线程的方法,程序运行都正确,但无法关闭窗口,不清楚是窗口无法通过关闭按钮来接受Windows消息,还是接受了 ...

  5. git (转载)

    文章转载 一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的 ...

  6. SQL 系统表应用

    查看link server select DD.System,DD.DB,DD.previous_processing_dte, DD.processing_dte,LS.LinkServerName ...

  7. 有关Option.inSamplSize 和 Compress 图片压缩

    1.图片占用内存:占用的内存 = 图片长度 * 图片宽度 * 单位像素占用的字节数 注: 图片长度和图片宽度就是图片在行列上的像素数量. 图片格式: ALPHA_8:表示8位Alpha位图,即A=8, ...

  8. 函数----Function对象

    函数---Function对象 一 .  函数的书写 函数 : 就是将一些语句进行封装,然后通过调用的形式,执行这些语句. 函数的作用 : ● 将大量重复的语句写在函数里,以后需要这些语句的时候,可以 ...

  9. windows定时计划备份MySql

    使用 MySql 的 mysqldump 将数据库文件备份成 sql 文件. Windows下备份 本地的数据库环境 MySql 安装环境:C:\MySql 数据库名称:bbs root root 数 ...

  10. 重新认识vue之事件阻止冒泡

    冒泡的表现 近期用vue做了一个需求,大概是同一个区域,点击不同位置有不同的响应函数,还有个总的响应函数,好吧,如下图所示: 他们的DOM结构如下: <div v-for="(item ...