spring多数据源分布式事务的分析与解决方案
一、概述
1、业务背景
对老系统进行重构合并,导致新系统需要同时对3个数据库进行管理。由于出现跨库业务,需要实现分布式事务。
2、开发环境
spring框架版本 4.3.10.RELEASE
持久层为结合mybatis写的领域模型,如

每一个entity对应数据库的一张表,@DataSource注解(自定义)了对应数据源的key值。所以一个业务中可能存在数据源的切换。
事务采用注解@Transaction驱动。
二、spring对多数据源的支持
spring框架通过抽象类AbstractRoutingDataSource来实现多数据源支持。
AbstractRoutingDataSource中有一个抽象方法determineCurrentLookupKey()。子类实现该方法即可。
举例如下:
package com.cmcc.cq.xx.common.mybatis;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return getDataSourceType();
}
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setDataSourceType(String dataSourceType){
contextHolder.set(dataSourceType);
}
public static String getDataSourceType(){
return contextHolder.get();
}
public static void clearDataSourceType(){
contextHolder.remove();
}
}
ThreadLocal保存当前线程的数据源,执行数据库操作之前会通过解析注解@DataSource设置下次操作的数据源类型,即相应的key值(见后文数据源配置)。

到此,在不使用事务的情况下,可以完成多数据源切换。
三、spring分布式事务支持
1、DataSourceTransactionManager不支持多数据源
DataSourceTransactionManager事务管理器是一个单数据源事务管理器,在实例化时候会注入一个数据源。
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource">
</property>
</bean>
注意:虽然我们注入的是一个动态数据源,但是DataSourceTransactionManager不会因为我们使用动态数据源而跟着变化。
因为DataSourceTransactionManager开始事务时获取数据库connection时并不是每次都通过dataSource来获取,一般都是通过ConnectionHolder类获得。

所以开启事务会报找不到表或视图的异常。
同时DataSourceTransactionManager也不能实现跨库事务的一致性。
2、JtaTransactionManager支持分布式事务
JtaTransactionManager事务管理器只是提供一个接入方式,并没有做相应的实现,目前比较流行的分布式事务第三方实现是atomikos和jotm。其中jotm更新日期是2010年,建议使用atomikos。
两者配置也是大同小异,以atomikos为例。
引入maven依赖
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>3.7.0</version>
</dependency>
首先是数据源的配置,必须要使用类com.atomikos.jdbc.AtomikosDataSourceBean,不能再使用其他的连接池替代。xaDataSourceClassName要根据数据库选择相应的类,在数据库对应的驱动包里可以找到。
<bean id="dataSource3" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close">
<property name="uniqueResourceName" value="key值"/>
<property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource"/>
<property name="xaProperties">
<props>
<prop key="URL">${jdbc.dataSource.url3}</prop>
<prop key="user">${jdbc.dataSource.username3}</prop>
<prop key="password">${jdbc.dataSource.password3}</prop>
</props>
</property>
<property name="minPoolSize" value="${jdbc.dataSource.minimumIdle3}" />
<property name="maxPoolSize" value="${jdbc.dataSource.maximumPoolSize3}" />
<property name="borrowConnectionTimeout" value="${jdbc.dataSource.connectionTimeout3}" />
<property name="testQuery" value="${jdbc.dataSource.connectionTestQuery3}" />
<property name="maintenanceInterval" value="60" />
<property name="maxIdleTime" value="${jdbc.dataSource.idleTimeout3}"></property>
</bean>
然后是JtaTransactionManager事务管理器配置。
JtaTransactionManager有两个重要属性需要配置transactionManager和userTransaction。对应的配置类如下:

注:在jotm中只需配置transactionManager属性
最后是atomikos的配置文件jta.properties。
配置路径:根路径

jta.properties也可命名为transactions.properties,如果不配置也可以启动项目,因为几乎所有配置项都有默认值。
transactions.properties配置

spring多数据源分布式事务的分析与解决方案的更多相关文章
- C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 VC中进程与进程之间共享内存 .net环境下跨进程、高频率读写数据 使用C#开发Android应用之WebApp 分布式事务之消息补偿解决方案
C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). ...
- Spring Boot2.0之多数据源分布式事务问题
分布式事务解决方案的问题, 分布式事务产生的原因: 多个不同的服务连接不同的数据源 ,做分布式事务的管理. 这种情况是连接两个数据源的情况,然后事务管理器是这样的 只管理了test02的这端业务代码. ...
- spring 多数据源一致性事务方案
spring 多数据源配置 spring 多数据源配置一般有两种方案: 1.在spring项目启动的时候直接配置两个不同的数据源,不同的sessionFactory.在dao 层根据不同业务自行选择使 ...
- SpringBoot 多数据源分布式事务
1.pom依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- (附源码gitHub下载地址)spring boot -jta-atomikos分布式事务
应用场景:双数据源,就是某些项目会涉及到两个数据源或者两个以上的数据源,这个多数据源的项目一般是数据同步,也就是把数据从另一个系统中,保存到另一个系统,两边的 数据库又不一样,比如一个Mysql.一个 ...
- spring boot:使用分布式事务seata(druid 1.1.23 / seata 1.3.0 / mybatis / spring boot 2.3.2)
一,什么是seata? Seata:Simpe Extensible Autonomous Transcaction Architecture, 是阿里中间件开源的分布式事务解决方案. 前身是阿里的F ...
- Spring Cloud Alibaba分布式事务组件 seata 详解(小白都能看懂)
一,什么是事务(本地事务)? 指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行. 简单的说,事务就是并发控制的单位,是用户定义的一个操作序列. 而一个逻辑工作单元要成 ...
- (WebFlux)003、多数据源R2dbc事务失效分析
一.背景 最近项目持续改造,然后把SpringMVC换成了SpringWebflux,然后把Mybatis换成了R2dbc.中间没有遇到什么问题,一切都那么的美滋滋,直到最近一个新需求的出现,打破了往 ...
- ELK(ElasticSearch, Logstash, Kibana) v5.3.2 分布式日志收集分析最佳解决方案 基于CentOS 7 ( 一 )
[root@localhost temp]# .tar.gz -C /usr/local/ [root@localhost temp]# vim logstatsh_test.conf ======= ...
随机推荐
- leaflet本地加载arcgis切片
var origin = [-20037700, 33711400];//图层起点坐标 var resolutions = [ 8466.6836000338681, // Level 0 4233. ...
- HTTP请求方法及常见状态码
GET: 请求指定的页面信息,并返回实体主体. HEAD: 只请求页面的首部. POST: 请求服务器接受所指定的文档作为对所标识的URI的新的从属实体. PUT: 从客户端向服务器传送的数据取代指定 ...
- ajax异步的加深理解
过去印象中的ajax的异步操作,一直还居然在$.ajax函数内部的异步,真是大错特错,实际的异步操作,是针对整个js文件来的. 今天总算意识到了,实际情况如下: $(function(){ //[弹框 ...
- STL中map的使用
知识点 C++中map提供的是一种键值对容器,里面的数据都是成对出现的.map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的. ...
- 制作MACOSX 10.9Mavericks安装启动U盘教程
苹果OS X Mavericks发布了,不少朋友又开始制作系统安装U盘了.其实下面介绍的方法与之前介绍的方法可能有些不同,不过原理还是一样的.下面看看具体的操作步骤吧! 1. 首先你需要开启显示隐藏文 ...
- yum命令不能使用的解决办法
以前yum命令一直是可用的,今天使用它安装命令时一直提示,如下图: 百度了一圈说是网络问题: 然后我就ping www.baidu.com 可以ping通啊 最后在同事的帮助下找到了解决办法: vi ...
- fiddler https 您的连接不是私密连接 解决方法(不明原理但是照着做成功了,记录下)
在桌面找到生成的证书 打开chrome chrome://settings/ 导入证书 再次运行fiddler,依次点击Tools下的Options,然后点HTTPS选项卡,再点击actions下的R ...
- getshell技巧-phpMyAdmin的利用
生活就是泥沙俱下,鲜花和荆棘并存.--毕淑敏 1.明确目标2.信息收集3.漏洞挖掘和利用 信息收集 明确路径 利用目录扫描工具,对目标网站进行扫描,获取网站目录.常用工具有Kali中的DirBuste ...
- iOS适配UIViewView/WKWebView,H5生成长图,仿微信进度条
前段时间撸代码猥琐发育的时候,设计师老王给了张截图某宝APP上一个生成长图分享的功能,正好公司有这个需求,于是在立马开始操练起来!在万能的度娘上搜集整理资料后发现很多文章介绍的方案对WKWebView ...
- C++走向远洋——26(项目二,2,构造函数与析构函数)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:game.cpp * 作者:常轩 * 微信公众号:Worldhe ...