一、引言

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

    花了 160 买了这个软件,至少看一遍它的 user guide,钱不能白花. https://kapeli.com/guide/guide.html 设置全局快捷键 Preference -> ...

  2. 顺序容器vector,deque,list的选用规则

    前言 常见的顺序容器主要有三种 - vector,deque,list.它们实现的功能相差不大,那么实际开发中该如何进行选择呢?本文将为你解答这个问题. 分析 由于这三种容器实现的数据结构原型不同(v ...

  3. poj1125--Floyd

    题解: 有N个股票经济人能够互相传递消息.他们之间存在一些单向的通信路径.如今有一个消息要由某个人開始传递给其它全部人.问应该由哪一个人来传递,才干在最短时间内让全部人都接收到消息. 显然,用Floy ...

  4. ZooKeeper学习笔记(一)

    引导 刚开始学习ZooKeepter,看的书是[O'Reilly Media] ZooKeeper.下面的内容基本上是该书的翻译,很多语句也存在问题,大致读还是没问题的,自己在学习中记录. 第一章 Z ...

  5. mongoose基于mongodb的数据评论设计

    var CommentSchema = { data:{type: ObjectId, ref:'Data'}, //Data数据表,此处存数据id from:{type: ObjectId, ref ...

  6. window.onerror 错误监听,发到后台

    var doc = document.body || document.documentElement; var _onerror = Onerror(''); var Onerror = funct ...

  7. socket基本使用

    UDP发送和接收 MainRecv.cpp #include <iostream> #include <WinSock2.h> #include <sstream> ...

  8. 【操作系统】使用BCD工具安装Ubuntu操作系统

    Ubuntu14.04作为目前最新版本的ubuntu系统,相信很多人都想在自己的电脑上安装一下,然而系统的安装方法各式各样,U盘法.grub引导法等等,本文将介绍在win7系统下用easyBCD软件建 ...

  9. 02-线性结构1 两个有序链表序列的合并(15 point(s)) 【链表合并】

    02-线性结构1 两个有序链表序列的合并(15 point(s)) 本题要求实现一个函数,将两个链表表示的递增整数序列合并为一个非递减的整数序列. 函数接口定义: List Merge( List L ...

  10. ansible 基础知识

    英文官网,值得拥有! http://docs.ansible.com/ansible/list_of_files_modules.html# 摘自: http://blog.csdn.net/b624 ...