Springboot2 integrates JTA components and manages multi data source transactions

Time:2021-3-5

Source code: GitHub. Click here | gitee. Click here

1、 Introduction to JTA components

1. Basic concepts of JTA

JTA is java transaction API. JTA allows applications to perform distributed transaction processing, that is, to access and update data on two or more network computer resources. Jdbc driver’s support for JTA greatly enhances the ability of data access.

Xa protocol is a set of distributed transaction management specifications at the database level. JTA is the implementation of XA protocol in Java. Multiple databases or message manufacturers implement JTA interface. Developers only need to call spring JTA interface to realize JTA transaction management function.

JTA transactions are more powerful than JDBC transactions. A JTA transaction can have multiple participants, while a JDBC transaction is limited to a single database connection. Any of the following Java platform components can participate in a JTA transaction

2. Distributed transaction

Distributed transaction includes transaction manager and one or more resource managers supporting XA protocol.

Resource manager is any type of persistent data storage container, such as relational databases commonly used in development: MySQL, Oracle, message middleware rocketmq, rabbitmq, etc.

Transaction manager provides transaction declaration, transaction resource management, synchronization, transaction context propagation and other functions, and is responsible for the communication of all transaction participants. JTA specification defines the interface between transaction manager and other transaction participants, and other transaction participants interact with transaction manager.

2、 Springboot integrates JTA

Overall structure of the project

Springboot2 integrates JTA components and manages multi data source transactions

1. Core dependence

<! -- springboot core dependency -- >
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<! -- JTA component core dependency -- >
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

2. Environment configuration

The configuration of jtamanager is very important in log output.

spring:
  jta:
    transaction-manager-id: jtaManager
  #Data source configuration
  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. Core container

Here two database connection configuration method is the same, you can download and read in the source code. The basic idea is to give the data source to JTA component for unified management to facilitate transaction communication.

Data source parameters

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

JTA component configuration

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 () {

        //Set up database connection
        MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
        mysqlXADataSource.setUrl(druidOneParam.getDbUrl());
        mysqlXADataSource.setUser(druidOneParam.getUsername());
        mysqlXADataSource.setPassword(druidOneParam.getPassword());
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);

        //Transaction manager
        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{
        //Configure session factory
        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) {
        //Configure session template
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

4. Test comparison

Here, we compare the test results of the two methods. When operating data between two data sources, we only need to add @ transactional annotation to the interface method to ensure the consistency of data between two data sources.

@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);
    }
}

3、 Summary of JTA components

JTA implements transaction management of multiple data sources in a relatively simple way. Through two-stage submission, transactions of multiple data sources can be managed at the same time. However, the exposed problem is also very obvious, which is a serious performance problem. Due to the simultaneous operation of multiple data sources, if one of the data sources takes too long to obtain data, the whole request will be very long. If the transaction time is too long, the data locking time will be too long, which will naturally lead to low performance and low throughput.

Therefore, in the actual development process, the system with high performance requirements rarely uses JTA components for transaction management. As a lightweight distributed transaction solution, it is worth trying in a small system.

Finally, as an API under Java, the principle and usage are worth learning to broaden our horizons and ideas.

4、 Source code address

GitHub · address
https://github.com/cicadasmile/middle-ware-parent
Gitee · address
https://gitee.com/cicadasmile/middle-ware-parent

Springboot2 integrates JTA components and manages multi data source transactions

Recommended reading: spring boot Advanced Series

Serial number Article title
01 Boot2 integrates shard JDBC middleware to realize database and table division
02 Boot2 integrates JavaMail to realize the function of sending mail asynchronously
03 Boot2 integrates rocketmq to realize asynchronous processing of requests
04 Boot2 integrates swagger2 to build interface management interface
05 Boot2 integrates quartjob to realize real-time timer management
06 Boot2 integrates redis cluster to realize message queue scenario
07 Boot2 integrates Dubbo framework to realize remote call of RPC service
08 Boot2 integrates elasticsearch framework to realize high performance search engine
09 Boot2 integrates JWT framework to solve the problem of token cross domain verification
10 Boot2 integrates fastdfs middleware to realize file distribution management
11 Boot2 integrates Shiro framework to realize user rights management
12 Boot2 integrates security framework to realize user rights management
13 Boot2 integrates the Clickhouse database to achieve high-performance data query and analysis
14 Boot2 integrates drools rule engine to realize efficient business rules
15 Boot2 integrates multiple data sources and configures mybatisplus enhanced plug-in
16 Boot2 integrates zookeeper components to manage service coordination in the architecture
17 Boot2 integrates Nacos components, builds environment and explains entry cases in detail
18 File system (01): Based on boot2 framework, manage excel and PDF
18 File system (02): Based on boot2 framework, manage XML and CSV
19 Boot2 integrates Kafka components, application cases and process details
20 Boot2 integrates elasticjob framework and customizes management process