一、添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>cn.edu.tju</groupId>
<artifactId>springbootatomikos</artifactId>
<version>1.0-SNAPSHOT</version>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
</parent>


<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>


<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
</dependency>

</dependencies>


</project>

二、在application.properties中配置多个数据源

spring.datasource.first.url=jdbc:mysql://xxx.xxx.xxx.xxx:3306/test?useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.first.user=root
spring.datasource.first.password=MyPass

spring.datasource.second.url=jdbc:mysql://xxx.xxx.xxx.xxx:3306/appbyte?useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.second.user=root
spring.datasource.second.password=MyPass

三、在配置类中创建2个数据源bean,2个jdbcTemplate,并创建JTA事物管理器

package cn.edu.tju.config;


import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.jta.JtaTransactionManager;

import javax.sql.DataSource;
import javax.transaction.UserTransaction;
import java.util.Properties;


@Configuration
public class MyConfig {

@ConfigurationProperties(prefix = "spring.datasource.first")
@Bean
public Properties firstProperties() {
return new Properties();
}

@Bean(name = "firstDataSource")
@Primary
public DataSource firstDataSource() {
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
ds.setXaDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");
ds.setUniqueResourceName("firstResource");
ds.setXaProperties(firstProperties());
return ds;
}

@Bean
@Primary
public JdbcTemplate firstJdbcTemplate(@Qualifier("firstDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}

@ConfigurationProperties(prefix = "spring.datasource.second")
@Bean
public Properties secondProperties() {
return new Properties();
}

@Bean(name = "secondDataSource")
public DataSource secondDataSource() {
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
ds.setXaDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");
ds.setUniqueResourceName("secondResource");
ds.setXaProperties(secondProperties());

return ds;
}

@Bean
public JdbcTemplate secondJdbcTemplate(@Qualifier("secondDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}

//JtaTransactionManager
@Bean
public JtaTransactionManager jtaTransactionManager () {
UserTransactionManager userTransactionManager = new UserTransactionManager();
UserTransaction userTransaction = new UserTransactionImp();
return new JtaTransactionManager(userTransaction, userTransactionManager);
}

}

四、在controller中分别使用2个jdbcTemplate操作2个数据库,分别尝试SQL正常情况和SQL异常情况

package cn.edu.tju.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class TestController {

@Qualifier("firstJdbcTemplate")
@Autowired
private JdbcTemplate firstJdbcTemplate;

@Qualifier("secondJdbcTemplate")
@Autowired
private JdbcTemplate secondJdbcTemplate;

@Transactional(rollbackFor = Exception.class, value = "jtaTransactionManager")
@RequestMapping("/test1")
public String test1() {
firstJdbcTemplate.execute("insert into user (username, password) values ('amadeus', 'liu');");
secondJdbcTemplate.execute("insert into user (username, password) values ('amadeus2', 'keep');");
return "ok";


}

@Transactional(rollbackFor = Exception.class, value = "jtaTransactionManager")
@RequestMapping("/test2")
public String test2() {
firstJdbcTemplate.execute("insert into user (username, password) values ('amadeus3', 'liu');");
secondJdbcTemplate.execute("insert into user (username, password) values22 ('amadeus4', 'go');");
return "ok";


}

}