如何处理spring事务与多数据源冲突问题?

关于Spring的事务,它是Spring Framework中极其重要的一块。前面用了大量的篇幅从应用层面、原理层面进行了比较全方位的一个讲解。但是因为它过于重要,所以本文继续做补充内容:Spring事务的同步机制(后面还有Spring事务的监听机制)

Spring事务同步机制?我估摸很多小伙伴从来没听过还有这么一说法,毕竟它在平时开发中你可能很少遇到(如果你没怎么考虑过系统性能和吞吐量的话)。

让我记录本文的源动力是忆起两年前自己在开发、调试过程中遇到这样一个诡异异常:

预期结果:本以为第二个insert是插入不进去的(不是报错,而是持久化不了),但是最终结果是:两条记录都插入成功了。

what a fuck,有点打我脸,挺疼。,与我之前掌握的理论相悖了,与Spring的javadoc里讲述的也相悖了(其实与Spring的并没有相悖,毕竟人家说的是“可能”,可见话不能说太满的重要性,哈哈)。这勾起了我的深入探索,究竟咋回事呢???

下面我把我的研究结果直接描述如下:

// 事务正常提交后 当然triggerAfterCompletion方法上面回滚里有而有个执行 此处不贴出了 因此我继续猜测:connection的自动提交功能可能是在这期间被恢复了,从而导致了这条SQL语句它的自动提交成功。

关于Connection的自动提交机制,以及事务对它的“影响干预”,请参与上面的推荐博文了解,有详细的表述

 // 这里最终都会被执行~~~
 // 子类可以根据自己的需要,自己去实现事务提交完成后的操作
 
// 这里是关键,在事后会恢复链接的自动提交本能,也就是常用的恢复现场机制嘛~~

这个内部类很简单,就是聚合了一些属性值,此处我们只关注mustRestoreAutoCommit这个属性值是否被设置为true了,若被设置过,就符合我的预期和猜想了。


此处代码也就是当开启事务(doBegin)的时候的关键代码,它对DataSourceTransactionObject打入标记,表示最终需要事务它返还给链接自动提交的能力。

综上所述:上述案例Demo最终成功插入了两条数据的结果是完全正确,且我的猜想都解释通了。

备注:case2我本想构造的是在afterCommit()里使用connection而最终被错误关闭的情况case,目前来看若使用的是DataSourceTransactionManager这个事务管理器的话,是不用担心这种情况发生的,最终你的SQL都会被成功提交,也不会出现被误close掉的问题~


这一篇文章的主旨是讲解Spring事务的同步机制,虽然这以能力可能是Spring提供的小众功能,但正所谓小脾气、大能力描述它就很贴切~

我认为如果你真的想去了解一门技术的时候,还是不要放过每一个细节,把它融汇贯通,这样再学习一个新的技术就很容易举一反三了。(因为没有一句代码、注释都是无用的,否则它是废代码,就没有存在的必要)

最后可以分享一个找问题的小小小技巧:大胆猜测,小心求证

最近开始一步一步的学习springboot框架,同时在这里分享学习笔记。今天主要针对订单,会员两个模块调用各自的数据库,在springboot配置两个数据源以及事务整合配置。

2.1调用需要的依赖包

之前我们配置文件都是用properties文件,后来发现yml文件的配置比较轻便,所以后面配置我都会使用yml文件。如果不懂yml和properties文件的区别,可以自行百度。这里在resource包下创建application.yml文件,配置如下。这里需要注意的是,在springboot2中有个bug,如果配置多数据源,数据库的地址需要写成

我们之前的ssh框架对于数据库的调用一般是写在xml文件中,而springboot将这些配置简化,可以直接通过注解在class中实现。其实原理也是一样的,也是只是将在xml中实现的数据库调用,事务管理,session工厂创建等等操作放在class实现,然后再通过@MapperScan注解将不同的数据源进行不同文件夹的映射配置,以便调用。这里直接贴上我的member数据库和order数据库的调用配置

* 创建会员事务管理器

这个就没什么了,跟我们平时一样通过@controller声明类,再通过@Autowired引入持久层执行语句即可,当然这里是为了方便直接引入,省去了service层操作,而这里的mapper就是dao层。

编写springboot.class启动springboot项目即可。然后调用两个controller看看数据库是否添加数据,如果添加说明配置多数据源成功!

同上,先献上我的包结构

由于我们事务回滚一般是在业务层进行处理的,所以这里就不偷懒了,还是乖乖的建立一个service层,然后通过@Autowired引入持久层供controller层使用。
单事务管理相对来说会比较简单点。回顾前面的内容,前面我们在两个数据源的config文件各自配置了对应的数据源的bean==>DataSourceTransactionManager,所以如果需要使用引入这个事务管理即可,如下:

然后service层也创建对应的方法

这样子当service出错时,便可以回滚事务,防止数据插入数据库。但是以上的代码是针对于member模块的事务操作,如果在insert的方法里加上order模块的插入操作,这时候如果service方法出错,order模块的sql会回滚吗?显然是不会的,所以为了防止这种情况的出现,我们需要整合多数据源的事务管理。

我要回帖

更多关于 springboot多数据源事务 的文章

 

随机推荐