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、核心依賴

<!--SpringBoot核心依賴-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--JTA組件核心依賴-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

2、環境配置

這里jtaManager的配置,在日志輸出中非常關鍵。

spring:
  jta:
    transaction-manager-id: jtaManager
  # 數據源配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    data01:
      driverClassName: com.mysql.jdbc.Driver
      dbUrl: jdbc:mysql://localhost:3306/data-one
      username: root
      password: 000000
    data02:
      driverClassName: com.mysql.jdbc.Driver
      dbUrl: jdbc:mysql://localhost:3306/data-two
      username: root
      password: 000000

3、核心容器

這里兩個數據庫連接的配置手法都是一樣的,可以在源碼中自行下載閱讀。基本思路都是把數據源交給JTA組件來統一管理,方便事務的通信。

數據源參數

@Component
@ConfigurationProperties(prefix = "spring.datasource.data01")
public class DruidOneParam {
    private String dbUrl;
    private String username;
    private String password;
    private String driverClassName;
}

JTA組件配置

package com.jta.source.conifg;

@Configuration
@MapperScan(basePackages = {"com.jta.source.mapper.one"},sqlSessionTemplateRef = "data01SqlSessionTemplate")
public class DruidOneConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(DruidOneConfig.class) ;

    @Resource
    private DruidOneParam druidOneParam ;

    @Primary
    @Bean("dataSourceOne")
    public DataSource dataSourceOne () {

        // 設置數據庫連接
        MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
        mysqlXADataSource.setUrl(druidOneParam.getDbUrl());
        mysqlXADataSource.setUser(druidOneParam.getUsername());
        mysqlXADataSource.setPassword(druidOneParam.getPassword());
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);

        // 事務管理器
        AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
        atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);
        atomikosDataSourceBean.setUniqueResourceName("dataSourceOne");
        return atomikosDataSourceBean;
    }

    @Primary
    @Bean(name = "sqlSessionFactoryOne")
    public SqlSessionFactory sqlSessionFactoryOne(
            @Qualifier("dataSourceOne") DataSource dataSourceOne) throws Exception{
        // 配置Session工廠
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSourceOne);
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sessionFactory.setMapperLocations(resolver.getResources("classpath*:/dataOneMapper/*.xml"));
        return sessionFactory.getObject();
    }

    @Primary
    @Bean(name = "data01SqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(
            @Qualifier("sqlSessionFactoryOne") SqlSessionFactory sqlSessionFactory) {
        // 配置Session模板
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

4、測試對比

這里通過兩個方法測試結果做對比,在兩個數據源之間進行數據操作時,只需要在接口方法加上@Transactional注解即可,這樣保證數據在兩個數據源間也可以保證一致性。

@Service
public class TransferServiceImpl implements TransferService {

    @Resource
    private UserAccount01Mapper userAccount01Mapper ;

    @Resource
    private UserAccount02Mapper userAccount02Mapper ;

    @Override
    public void transfer01() {
        userAccount01Mapper.transfer("jack",100);
        System.out.println("i="+1/0);
        userAccount02Mapper.transfer("tom",100);
    }

    @Transactional
    @Override
    public void transfer02() {
        userAccount01Mapper.transfer("jack",200);
        System.out.println("i="+1/0);
        userAccount02Mapper.transfer("tom",200);
    }
}

三、JTA組件小結

在上面JTA實現多數據源的事務管理,使用方式還是相對簡單,通過兩階段的提交,可以同時管理多個數據源的事務。但是暴露出的問題也非常明顯,就是比較嚴重的性能問題,由於同時操作多個數據源,如果其中一個數據源獲取數據的時間過長,會導致整個請求都非常的長,事務時間太長,鎖數據的時間就會太長,自然就會導致低性能和低吞吐量。

因此在實際開發過程中,對性能要求比較高的系統很少使用JTA組件做事務管理。作為一個輕量級的分布式事務解決方案,在小的系統中還是值得推薦嘗試的。

最后作為Java下的API,原理和用法還是值得學習一下,開闊眼界和思路。

四、源代碼地址

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

推薦閱讀:SpringBoot進階系列

序號 文章標題
01 Boot2 整合 shard-jdbc 中間件,實現數據分庫分表
02 Boot2 整合 JavaMail ,實現異步發送郵件功能
03 Boot2 整合 RocketMQ ,實現請求異步處理
04 Boot2 整合 Swagger2 ,構建接口管理界面
05 Boot2 整合 QuartJob ,實現定時器實時管理
06 Boot2 整合 Redis集群 ,實現消息隊列場景
07 Boot2 整合 Dubbo框架 ,實現RPC服務遠程調用
08 Boot2 整合 ElasticSearch框架,實現高性能搜索引擎
09 Boot2 整合 JWT 框架,解決Token跨域驗證問題
10 Boot2 整合 FastDFS 中間件,實現文件分布管理
11 Boot2 整合 Shiro 框架,實現用戶權限管理
12 Boot2 整合 Security 框架,實現用戶權限管理
13 Boot2 整合 ClickHouse數據庫,實現數據高性能查詢分析
14 Boot2 整合 Drools規則引擎,實現高效的業務規則
15 Boot2 整合 多數據源,配置MybatisPlus增強插件
16 Boot2 整合 Zookeeper組件,管理架構中服務協調
17 Boot2 整合Nacos組件,環境搭建和入門案例詳解
18 文件系統(01):基於Boot2框架,管理Excel和PDF
18 文件系統(02):基於Boot2框架,管理Xml和CSV
19 Boot2 整合 Kafka組件,應用案例和流程詳解
20 Boot2 整合 ElasticJob框架,定制化管理流程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM