Spring + mybatis + mysql 使用事物的几种姿势

Posted 一灰灰blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring + mybatis + mysql 使用事物的几种姿势相关的知识,希望对你有一定的参考价值。



主要记录下spring是如何支持事物的,以及在Spring结合mybatis时,可以怎么简单的实现数据库的事物功能

I. 前提

case1:两张表的的事物支持情况

首先准备两张表,一个user表,一个story表,结构如下

Spring + mybatis + mysql 使用事物的几种姿势

我们的事物场景在于用户修改name时,要求两张表的name都需要一起修改,不允许出现不一致的情况

case2:单表的事物支持

转账,一个用户减钱,另一个用户加钱

Spring + mybatis + mysql 使用事物的几种姿势

相比上面那个case,这个更加简单了,下面的实例则主要根据这个进行说明,至于case1,则留待扩展里面进行

首先是实现对应的dao和entity

Spring + mybatis + mysql 使用事物的几种姿势

对应的mapper文件为

Spring + mybatis + mysql 使用事物的几种姿势


对应的mybatis连接数据源的相关配置

Spring + mybatis + mysql 使用事物的几种姿势


II. 实例演示

通过网上查询,Spring事物管理总共有四种方式,下面逐一进行演示,每种方式是怎么玩的,然后看实际项目中应该如何抉择

1. 硬编码方式

编程式事物管理,既通过TransactionTemplate来实现多个db操作的事物管理

a. 实现

那么,我们的转账case可以如下实现

Spring + mybatis + mysql 使用事物的几种姿势

主要看上面的transfor方法,内部通过 transactionTemplate 来实现事物的封装,内部有三个db操作,一个查询,两个更新,具体分析后面说明

上面的代码比较简单了,唯一需要关注的就是transactionTemplate这个bean如何定义的,xml文件中与前面重复的就不贴了,直接贴上关键代码, 一个是根据DataSource创建的TransactionManager,一个则是根据TransactionManager创建的TransactionTemplate

Spring + mybatis + mysql 使用事物的几种姿势


b. 测试用例

正常演示情况, 演示没有任何异常,不考虑并发的情况

Spring + mybatis + mysql 使用事物的几种姿势


输出如下,两个账号的钱都没有问题

Spring + mybatis + mysql 使用事物的几种姿势


转账过程中出现异常,特别是转账方钱已扣,收款方还没收到钱时,也就是case中的status为1的场景

Spring + mybatis + mysql 使用事物的几种姿势

对此,我们希望把转账方的钱还回去, 输出如下,发现两个的钱都没有变化

Spring + mybatis + mysql 使用事物的几种姿势


当status为2,表示在转账人钱已扣,收款人钱没收到之间,又有人给收款人转了200,此时根据mysql的锁机制,另外人的转账应该是立马到的(因为收款人账号没有被锁住),且金额不应该有问题

输出结果如下:

Spring + mybatis + mysql 使用事物的几种姿势


当status为3, 表示在转账人钱已扣,收款人钱没收到之间,又有人给转账人转了200,这时因为转账人的记录以及被加了写锁,因此只能等待转账的事物提交之后,才有可能+200成功,当然最终的金额也得一致

输出结果如下

Spring + mybatis + mysql 使用事物的几种姿势

c. 小结

至此,编程式事物已经实例演示ok,从上面的过程,给人的感觉就和直接写事物相关的sql一样,

Spring + mybatis + mysql 使用事物的几种姿势


2. 基于TransactionProxyFactoryBean方式

接下来的三个就是声明式事物管理,这种用得也比较少,因为需要每个事物管理类,添加一个TransactionProxyFactoryBean

a. 实现

除了将 TransactionTemplate 干掉,并将内部的sql逻辑移除之外,对比前面的,发现基本上没有太多差别

Spring + mybatis + mysql 使用事物的几种姿势


重点来了,主要是需要配置一个 TransactionProxyBeanFactory,我们知道BeanFactory就是我们自己来创建Bean的一种手段,相关的xml配置如下

Spring + mybatis + mysql 使用事物的几种姿势

通过上面的配置,大致可以了解到这个通过TransactionProxyFactoryBean就是创建了一个FactoryBeanDemo2的代理类,这个代理类内部封装好事物相关的逻辑,可以看做是前面编程式的一种简单通用抽象

b. 测试

测试代码与前面基本相同,唯一的区别就是我们使用的应该是上面BeanFactory生成的Bean,而不是直接使用FactoryBeanDemo2

正常演示case:

Spring + mybatis + mysql 使用事物的几种姿势

输出

Spring + mybatis + mysql 使用事物的几种姿势


status为1,内部异常的情况下,我们希望钱也不会有问题

Spring + mybatis + mysql 使用事物的几种姿势


输出为

Spring + mybatis + mysql 使用事物的几种姿势


status为2 时,分析结果与上面应该相同,输出如下

Spring + mybatis + mysql 使用事物的几种姿势


status为3时,输出

Spring + mybatis + mysql 使用事物的几种姿势


c. 小结

TransactionProxyFactoryBean 的思路就是利用代理模式来实现事物管理,生成一个代理类,拦截目标方法,将一组sql的操作封装到事物中进行;相比较于硬编码,无侵入,而且支持灵活的配置方式

缺点也显而易见,每个都要进行配置,比较繁琐

3. xml使用方式

Spring有两大特点,IoC和AOP,对于事物这种情况而言,我们可不可以使用AOP来做呢?

对于需要开启事物的方法,拦截掉,执行前开始事物,执行完毕之后提交事物,出现异常时回滚

这样一看,感觉还是蛮有希望的,而下面两种姿势正是这么玩的,因此需要加上aspect的依赖

Spring + mybatis + mysql 使用事物的几种姿势


a. 实现

java类与第二种完全一致,变动的只有xml

Spring + mybatis + mysql 使用事物的几种姿势

观察上面的配置,再想想第二种方式,思路都差不多了,但是这种方式明显更加通用,通过切面和切点,可以减少大量的配置

b. 测试

Spring + mybatis + mysql 使用事物的几种姿势


这个测试起来,和一般的写法就没啥两样了,比第二种的FactoryBean的注入方式简单点

正常输出

Spring + mybatis + mysql 使用事物的几种姿势


status=1 出现异常时,输出

Spring + mybatis + mysql 使用事物的几种姿势


status=2 转账过程中,又存钱的场景,输出,与前面预期一致

Spring + mybatis + mysql 使用事物的几种姿势


status=3 的输出,与前面预期一致

Spring + mybatis + mysql 使用事物的几种姿势


4. 注解方式

这个就是消灭xml,用注解来做的方式,就是将前面xml中的配置用 @Transactional注解替换

a. 实现

Spring + mybatis + mysql 使用事物的几种姿势


因此需要在xml中配置,开启事物注解

这样一看,就更加清晰了,实际项目中,xml和注解方式也是用得最多的场景了

b. 测试case

和第三种测试case完全相同, 输出结果也一样,直接省略

III. 小结

上面说了Spring中四种使用事物的姿势,其中硬编码方式可能是最好理解的,就相当于将我们写sql中,使用事物的方式直接翻译成对应的java代码了;而FactoryBean方式相当于特殊情况特殊对待,为每个事物来一个代理类来增强事物功能;后面的两个则原理差不多都是利用事物通知(AOP)来实现,定义切点及相关信息

编程式:

  • 注入 TransactionTemplate

  • 将利用事物的逻辑封装到 transactionTemplate#execute方法内

代理BeanFactory:

  • 利用 TransactionProxyFactoryBean 为事物相关类生成代理

  • 使用方通过FactoryBean获取代理类,作为使用的Bean

xml配置:

  • 利用 tx标签 + aop方式来实现

  • <tx:advice> 标签定义事物通知,内部可有较多的配置信息

  • <aop:config> 配置切点,切面

注解方式:

  • 在开启事物的方法or类上添加 @Transactional 注解即可

  • 开启事物注解 <tx:annotation-driven transaction-manager="transactionManager"/>

IV. 其他

1. 参考

文档

  • Spring事务管理的四种方式

源码

  • 项目源码:https://gitee.com/liuyueyi/study-demo/tree/master/dao

  • 主要查看包路径: https://gitee.com/liuyueyi/study-demo/tree/master/dao/src/main/java/com/git/hui/demo/mybatis/repository/transaction

  • 测试相关代码: https://gitee.com/liuyueyi/study-demo/tree/master/dao/src/test/java/com/git/hui/demo/test/transaction


2.  一灰灰Blog: https://liuyueyi.github.io/hexblog

基于hexo + github pages搭建的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

3. 声明

尽信书则不如,已上内容,纯属一家之言,因本人能力一般,见识有限,如发现bug或者有更好的建议,随时欢迎批评指正

  • QQ: 一灰灰/3302797840

4. 扫描关注


以上是关于Spring + mybatis + mysql 使用事物的几种姿势的主要内容,如果未能解决你的问题,请参考以下文章

Spring+SpringMVC+Mybatis+Mysql整合实例

spring、mysql、mybatis测试

mybatis 学习二 MyBatis简介与配置MyBatis+Spring+MySql

MyBatis学习 之 一MyBatis简介与配置MyBatis+Spring+MySql

MyBatis简介与配置MyBatis+Spring+MySql

Spring Boot集成 MyBatis 操作 MySQL 8