[TOC]
# 目录
## 整合步骤
1. 准备工作
2. 新增依赖
3. 编写YAML样式的配置
4. 编写实体类读取配置
5. 编写多数据源与管理事务配置类
6. 测试效果
> 官网地址: https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-jta
### 一、准备工作
1.1 构建SpringBoot项目 <br>
1.2 《[Linux搭建MySQL主从](https://blog.eddilee.cn/archives/linux%E6%90%AD%E5%BB%BAmysql%E4%B8%BB%E4%BB%8E)》基础上追加库表
```sql
CREATE DATABASE `xa_246` CHARACTER SET 'utf8mb4'
CREATE TABLE `xa_246`.`xa_246` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
)
CREATE DATABASE `xa_247` CHARACTER SET 'utf8mb4'
CREATE TABLE `xa_247`.`xa_247` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
)
```
### 二、新增依赖
```xml
<!-- 使用jta+atomikos管理多数据源事务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
```
### 三、编写YAML样式的配置
```yml
spring:
application:
name: jta_atomikos
mysql:
datasource:
db246:
url: "jdbc:mysql://192.168.8.246/xa_246"
user: "eddie"
password: "Abc@123456"
uniqueresourcename: "dataSource246"
db247:
url: "jdbc:mysql://192.168.8.247/xa_247"
user: "eddie"
password: "Abc@123456"
uniqueresourcename: "dataSource247"
```
### 四、编写实体类读取配置
db246
```java
@Data
@Configuration
@ConfigurationProperties(prefix = "mysql.datasource.db246")
public class DbConfig246 {
private String url;
private String user;
private String password;
private String uniqueresourcename;
}
```
db247
```java
@Data
@Configuration
@ConfigurationProperties(prefix = "mysql.datasource.db247")
public class DbConfig247 {
private String url;
private String user;
private String password;
private String uniqueresourcename;
}
```
### 五、编写多数据源与管理事务配置类
db246
```java
@Configuration
@MapperScan(value = "com.example.xademo.db246.dao", sqlSessionFactoryRef = "sqlSessionFactoryBean246")
public class ConfigDb246 {
@Bean("dataSource246")
public DataSource dataSource246(DbConfig246 dbConfig246) {
// MySQL <scope>runtime</scope> 会导致引入不了的
MysqlXADataSource xaDataSource = new MysqlXADataSource();
xaDataSource.setUser(dbConfig246.getUser());
xaDataSource.setPassword(dbConfig246.getPassword());
xaDataSource.setUrl(dbConfig246.getUrl());
// Atomikos管理
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSource(xaDataSource);
atomikosDataSourceBean.setUniqueResourceName(dbConfig246.getUniqueresourcename());
// 返回 Atomikos 的数据源
return atomikosDataSourceBean;
}
@Bean("sqlSessionFactoryBean246")
public SqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dataSource246") DataSource dataSource) throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
// 设置Mybatis
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resourceResolver.getResources("mybatis/dataSource246/*.xml"));
return sqlSessionFactoryBean;
}
/**
* 事务管理器
*/
@Bean("xaTransaction")
public JtaTransactionManager jtaTransactionManager() {
UserTransaction userTransaction = new UserTransactionImp();
UserTransactionManager userTransactionManager = new UserTransactionManager();
return new JtaTransactionManager(userTransaction, userTransactionManager);
}
}
```
db247
```java
@Configuration
@MapperScan(value = "com.example.xademo.db247.dao", sqlSessionFactoryRef = "sqlSessionFactoryBean247")
public class ConfigDb247 {
@Bean("dataSource247")
public DataSource dataSource247(DbConfig247 dbConfig247) {
// MySQL <scope>runtime</scope> 会导致引入不了的
MysqlXADataSource xaDataSource = new MysqlXADataSource();
xaDataSource.setUser(dbConfig247.getUser());
xaDataSource.setPassword(dbConfig247.getPassword());
xaDataSource.setUrl(dbConfig247.getUrl());
// Atomikos管理
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setXaDataSource(xaDataSource);
atomikosDataSourceBean.setUniqueResourceName(dbConfig247.getUniqueresourcename());
// 返回 Atomikos 的数据源
return atomikosDataSourceBean;
}
@Bean("sqlSessionFactoryBean247")
public SqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dataSource247") DataSource dataSource) throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
// 设置Mybatis
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resourceResolver.getResources("mybatis/dataSource247/*.xml"));
return sqlSessionFactoryBean;
}
}
```
### 六、测试效果
启动类
```java
/**
* @author eddie.lee
*/
@SpringBootApplication
@EnableConfigurationProperties(value = {DbConfig246.class, DbConfig247.class})
public class XaDemoApplication {
public static void main(String[] args) {
SpringApplication.run(XaDemoApplication.class, args);
}
}
```
业务层
```java
@Service
public class XAService {
@Resource
private XA246Mapper xa246Mapper;
@Resource
private XA247Mapper xa247Mapper;
/**
* 指定事务管理器
*/
@Transactional(transactionManager = "xaTransaction")
public void testXA() {
XA246 xa246 = new XA246();
xa246.setId(1);
xa246.setName("xa_246");
xa246Mapper.insert(xa246);
XA247 xa247 = new XA247();
xa247.setId(1);
xa247.setName("xa_247");
xa247Mapper.insert(xa247);
}
}
```
单元测试
```java
@RunWith(SpringRunner.class)
@SpringBootTest
class XaDemoApplicationTests {
@Autowired
private XAService xaService;
@Test
void contextLoads() {
}
@Test
public void testXA() {
xaService.testXA();
}
}
```
1. 第一次运行,插入成功
2. 修改数据库"ALTER TABLE `xa_247`.`xa_247` MODIFY COLUMN `name` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL AFTER `id`"
3. 第二次运行,出现"### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column 'name' at row 1"的错误。
4. 查看数据库,246与247也没有插入,证明已经成效了分布式事务
> TIPS: Mycat 与 ShardingJdbc 默认已经开启XA事务管理
SpringBoot 整合jta+atomikos 解决分布式事务