SpringBoot2 整合JTA元件,多資料來源事務管理

知了一笑發表於2020-07-12

本文原始碼:GitHub·點這裡 || GitEE·點這裡

一、JTA元件簡介

1、JTA基本概念

JTA即Java-Transaction-API,JTA允許應用程式執行分散式事務處理,即在兩個或多個網路計算機資源上訪問並且更新資料。JDBC驅動程式對J他的支援極大地增強了資料訪問能力。

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框架,定製化管理流程

相關文章