SpringBoot2 整合JTA组件,多数据源事务管理

本文源码:GitHub·点这里 || GitEE·点这里

一、JTA组件简介

1、JTA基本概念

JTA即Java-Transaction-API,JTA允许应用程序执行分布式事务处理,即在两个或多个网络计算机资源上访问并且更新数据。JDBC驱动程序对JTA的支持极大地增强了数据访问能力。

XA协议是数据库层面的一套分布式事务管理的规范,JTA是XA协议在Java中的实现,多个数据库或是消息厂商实现JTA接口,开发人员只需要调用SpringJTA接口即可实现JTA事务管理功能。

JTA事务比JDBC事务更强大。一个JTA事务可以有多个参与者,而一个JDBC事务则被限定在一个单一的数据库连接。下列任一个Java平台的组件都可以参与到一个JTA事务中

2、分布式事务

分布式事务(DistributedTransaction)包括事务管理器(TransactionManager)和一个或多个支持 XA 协议的资源管理器 ( Resource Manager )。

资源管理器是任意类型的持久化数据存储容器,例如在开发中常用的关系型数据库:MySQL,Oracle等,消息中间件RocketMQ、RabbitMQ等。

事务管理器提供事务声明,事务资源管理,同步,事务上下文传播等功能,并且负责着所有事务参与单元者的相互通讯的责任。JTA规范定义了事务管理器与其他事务参与者交互的接口,其他的事务参与者与事务管理器进行交互。

二、SpringBoot整合JTA

项目整体结构图

1、核心依赖

1<!--SpringBoot核心依赖--> 2<dependency> 3 <groupId>org.springframework.boot</groupId> 4 <artifactId>spring-boot-starter-web</artifactId> 5</dependency> 6<!--JTA组件核心依赖--> 7<dependency> 8 <groupId>org.springframework.boot</groupId> 9 <artifactId>spring-boot-starter-jta-atomikos</artifactId> 10</dependency>

2、环境配置

这里jtaManager的配置,在日志输出中非常关键。

1spring: 2 jta: 3 transaction-manager-id: jtaManager 4 # 数据源配置 5 datasource: 6 type: com.alibaba.druid.pool.DruidDataSource 7 data01: 8 driverClassName: com.mysql.jdbc.Driver 9 dbUrl: jdbc:mysql://localhost:3306/data-one 10 username: root 11 password: 000000 12 data02: 13 driverClassName: com.mysql.jdbc.Driver 14 dbUrl: jdbc:mysql://localhost:3306/data-two 15 username: root 16 password: 000000

3、核心容器

这里两个数据库连接的配置手法都是一样的,可以在源码中自行下载阅读。基本思路都是把数据源交给JTA组件来统一管理,方便事务的通信。

数据源参数

1@Component 2@ConfigurationProperties(prefix = "spring.datasource.data01") 3public class DruidOneParam { 4 private String dbUrl; 5 private String username; 6 private String password; 7 private String driverClassName; 8}

JTA组件配置

1package com.jta.source.conifg; 2 3@Configuration 4@MapperScan(basePackages = {"com.jta.source.mapper.one"},sqlSessionTemplateRef = "data01SqlSessionTemplate") 5public class DruidOneConfig { 6 7 private static final Logger LOGGER = LoggerFactory.getLogger(DruidOneConfig.class) ; 8 9 @Resource 10 private DruidOneParam druidOneParam ; 11 12 @Primary 13 @Bean("dataSourceOne") 14 public DataSource dataSourceOne () { 15 16 // 设置数据库连接 17 MysqlXADataSource mysqlXADataSource = new MysqlXADataSource(); 18 mysqlXADataSource.setUrl(druidOneParam.getDbUrl()); 19 mysqlXADataSource.setUser(druidOneParam.getUsername()); 20 mysqlXADataSource.setPassword(druidOneParam.getPassword()); 21 mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true); 22 23 // 事务管理器 24 AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean(); 25 atomikosDataSourceBean.setXaDataSource(mysqlXADataSource); 26 atomikosDataSourceBean.setUniqueResourceName("dataSourceOne"); 27 return atomikosDataSourceBean; 28 } 29 30 @Primary 31 @Bean(name = "sqlSessionFactoryOne") 32 public SqlSessionFactory sqlSessionFactoryOne( 33 @Qualifier("dataSourceOne") DataSource dataSourceOne) throws Exception{ 34 // 配置Session工厂 35 SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); 36 sessionFactory.setDataSource(dataSourceOne); 37 ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 38 sessionFactory.setMapperLocations(resolver.getResources("classpath*:/dataOneMapper/*.xml")); 39 return sessionFactory.getObject(); 40 } 41 42 @Primary 43 @Bean(name = "data01SqlSessionTemplate") 44 public SqlSessionTemplate sqlSessionTemplate( 45 @Qualifier("sqlSessionFactoryOne") SqlSessionFactory sqlSessionFactory) { 46 // 配置Session模板 47 return new SqlSessionTemplate(sqlSessionFactory); 48 } 49}

4、测试对比

这里通过两个方法测试结果做对比,在两个数据源之间进行数据操作时,只需要在接口方法加上@Transactional注解即可,这样保证数据在两个数据源间也可以保证一致性。

1@Service 2public class TransferServiceImpl implements TransferService { 3 4 @Resource 5 private UserAccount01Mapper userAccount01Mapper ; 6 7 @Resource 8 private UserAccount02Mapper userAccount02Mapper ; 9 10 @Override 11 public void transfer01() { 12 userAccount01Mapper.transfer("jack",100); 13 System.out.println("i="+1/0); 14 userAccount02Mapper.transfer("tom",100); 15 } 16 17 @Transactional 18 @Override 19 public void transfer02() { 20 userAccount01Mapper.transfer("jack",200); 21 System.out.println("i="+1/0); 22 userAccount02Mapper.transfer("tom",200); 23 } 24}

三、JTA组件小结

在上面JTA实现多数据源的事务管理,使用方式还是相对简单,通过两阶段的提交,可以同时管理多个数据源的事务。但是暴露出的问题也非常明显,就是比较严重的性能问题,由于同时操作多个数据源,如果其中一个数据源获取数据的时间过长,会导致整个请求都非常的长,事务时间太长,锁数据的时间就会太长,自然就会导致低性能和低吞吐量。

因此在实际开发过程中,对性能要求比较高的系统很少使用JTA组件做事务管理。作为一个轻量级的分布式事务解决方案,在小的系统中还是值得推荐尝试的。

最后作为Java下的API,原理和用法还是值得学习一下,开阔眼界和思路。

四、源代码地址

1GitHub·地址 2https://github.com/cicadasmile/middle-ware-parent 3GitEE·地址 4https://gitee.com/cicadasmile/middle-ware-parent

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )