Spring中实现多数据源事务管理
本文内容纲要:
- 前言- 研究
- 进一步研究
- 题外话
文章转自 https://www.2cto.com/kf/201507/424229.html
前言
由于项目中引入了多个数据源,并且需要对多个数据源进行写操作,那么多数据源的事务管理自然成了不可避免的问题,这也让我对@Transactional
注解有了进一步的理解(但实际上也并不是非常深入)
然而这是一个演进的过程,刚开始项目中并没有使用@Transactional
指定具体的TransactionManager
,所以新增一个数据源后,对原有的事务产生了影响了,这也是偶尔在一次测试报错而结果没有回滚之后才发现的,遂对于@Transactional
注解的一些参数项进行了了解。
研究
由于容器中存在两个TransactionManager
,那么被@Transactional
注解的方法到底使用了哪个TransactionManager
来进行事务管理,抑或是同时使用了两个TransactionManager
来进行事务管理都是我们需要搞清楚的问题。
首先我们先看看@Transactional
注解上有没有提供配置项来指定TransactionManager
,果不其然,发现value
属性就是用来指定具体TransactionManager
的,通过id
或者name
来指定唯一一个TransactionManager
,那么对于只需要一个事务管理的方法,问题就简单多了:
?
1 2 3 4 |
|
关于不指定TransactionManager时会使用哪一个TransactionManager,有兴趣的童鞋可以参考另一篇文章,讲的比较清晰:https://blog.sina.com.cn/s/blog_8f61307b0100ynfb.html
好了,回到我们研究的问题,那么对于需要写入多个数据源的业务方法该怎么办呢?
进一步研究
看来@Transactional
是没有提供这种功能了,那么就自己写了一个吧。我记得Spring中的事务管理分编程式事务和声明式事务。我们平时使用的@Transactional
就是声明式事务,它的好处其实也就是灵活度更高、代码的耦合性更低,最终的事务管理实现还是一样的,只不过将具体逻辑都剥离到了切面中。所以我们可以手写一个切面来写一次“编程式事务”,当然在具体应用时,还是声明式的。
Java中一般编程式事务的写法:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
我们借用这个逻辑将事务管理相关提取到切面中,并在进入目标方法之前,让多个TransactionManager
都开启事务,并在成功执行后一并提交或失败后一并回滚,具体代码:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
|
整体结构很清晰:
- 首先根据指定的多个
TransactionManager
依次开启事务,这个次序不影响,因为其实大家都是平等的。 - 其次就是调用目标方法执行具体的业务逻辑
- 若是成功返回则提交每个事务,若中途报错,那么就回滚每个事务
其中为什么要用Stack
来保存TransactionManager
和TransactionStatus
呢?那是因为Spring的事务处理是按照LIFO/stack behavior的方式进行的。如若顺序有误,则会报错:
?
1 2 3 4 5 6 |
|
题外话
刚开始碰到这个问题的时候,先想到的是分布式事务管理,也去看了JTA相关的文章,但是好像比较麻烦,而且都是一些老文章,于是想试试自己实现,最后也实现了。所以想知道JTA TransactionManager
究竟有什么用呢?
本文内容总结:前言,研究,进一步研究,题外话,
原文链接:https://www.cnblogs.com/shuaiandjun/p/8667815.html
以上是 Spring中实现多数据源事务管理 的全部内容, 来源链接: utcz.com/z/362721.html