Although microservices are becoming more and more popular now, our system is also divided into many modular functions. The purpose of this is to make up for the lack of a single architecture. With the fragmentation of microservices, there is definitely a design for sub-libraries and sub-tables, but there is definitely a design for distributed transactions. The most typical example is
Bank transferFor example, if bank A transfers 500 yuan to bank B, the process must be bank A-500, bank B+500, in this process
Either we all succeed or we all die. First of all, the numbers of bank A and bank B must be in different databases. If in the transfer process, bank A first deposits the money -500, and then there is A problem when bank B+500, if the transaction is not rolled back, then there will be A problem of 500 yuan lost, that is, there is A problem
Transaction consistencyThe problem.




JTA + Atomikos solves distributed transactions

A, JTA

JTA (Java Transaction API) is one of the 13 development specifications for JavaEE. Java Transaction API, which allows applications to perform distributed transaction processing — accessing and updating data on two or more network computer resources. JTA support for JDBC drivers greatly enhances data access capabilities. The simplest and most direct purpose of transaction is to ensure the validity and consistency of data.


Second, the Atomikos

Atomikos is an open source class transaction manager that provides value-added services for the Java platform.


How it works: Distributed transactions include a transaction manager and an XA-enabled resource manager. The resource manager is our DB, and the transaction manager is responsible for regulating and controlling all transactions designed to participate in the DB.

Personal understanding: After Atomikos obtains the connection to the database, it will shield the transaction control at the bottom of the database, and then hand it over to Atomikos for unified scheduling and control.


Next, we simply do a distributed transaction control based on SpringBoot.
1. First we will import the maven libraries that need to be imported

<! <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jta-atomikos</artifactId> </dependency>Copy the code

2. Configure the data source



3. Configuration classes

The most important configuration

@Configuration
@MapperScan(basePackages = "com.example.mapper.db1", sqlSessionFactoryRef = "db1SqlSessionFactory")
public class DB1DataSourcesConfig {

    @Primary
    @Bean(name = "db1DataSource"Public DataSource DataSource (DB1Config DB1Config) {MysqlXADataSource = new MysqlXADataSource(); mysqlXADataSource.setUrl(DB1Config.getUrl_jdbc()); mysqlXADataSource.setUser(DB1Config.getUsername()); mysqlXADataSource.setPassword(DB1Config.getPassword()); mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true); AtomikosDataSourceBean = new AtomikosDataSourceBean(); atomikosDataSourceBean.setXaDataSource(mysqlXADataSource); atomikosDataSourceBean.setUniqueResourceName("db1DataSource");
        return atomikosDataSourceBean;
    }

    @Primary
    @Bean(name = "db1SqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/db1/*.xml"));

        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);

        sessionFactoryBean.setConfiguration(configuration);
        return sessionFactoryBean.getObject();
    }

    @Primary
    @Bean(name = "db1SqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        returnnew SqlSessionTemplate(sqlSessionFactory); }}Copy the code

So that’s basically the configuration, so I just wrote the configuration of one database, and the other one is just like this one, where the database information has changed.

4, test,


The design here is to modify two data, student name and student score, which are stored in different databases. We modify the user information through the interface, and then modify the user’s score information.

There is no data before modification

Let’s see if the user information can be rolled back if there is an exception when modifying the score.

The results of

First, the code reported an error at line 39. If we follow our logic, if we failed to modify the score, then the age of the corresponding user was also unsuccessful, but the result shows that the age of the user was changed anyway, obviously the interface is not managed by distributed transactions.



Let’s change the data back, and then we’ll go back
The transaction withLet’s see if that doesn’t happen. (
Methods add
@Transactional
Annotations can be)

The results of


After adding distributed transactions, you can see from the results that the previous data is also rolled back if the later results are incorrect.
It ensures the consistency of transactions and the security and accuracy of data.

conclusion: This is the whole process of JTA + Atomikos to implement distributed transactions. It is relatively simple to implement functions. The above tests are based on a single SpringBoot project, compared to real microservices. Transaction consistency management can also be done through MQ or Dubbo. I’ll share it with you when I study it later.


Making address:
https://github.com/liangbintao/distributed_transaction.git

For more information, please follow the wechat official account: The growth of a programmer