目录
整合步骤
- 准备工作
- 新增依赖
- 编写YAML样式的配置
- 编写实体类读取配置
- 编写多数据源与管理事务配置类
- 测试效果
官网地址: https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-jta
一、准备工作
1.1 构建SpringBoot项目
1.2 《Linux搭建MySQL主从》基础上追加库表
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`)
)
二、新增依赖
<!-- 使用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样式的配置
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
@Data
@Configuration
@ConfigurationProperties(prefix = "mysql.datasource.db246")
public class DbConfig246 {
private String url;
private String user;
private String password;
private String uniqueresourcename;
}
db247
@Data
@Configuration
@ConfigurationProperties(prefix = "mysql.datasource.db247")
public class DbConfig247 {
private String url;
private String user;
private String password;
private String uniqueresourcename;
}
五、编写多数据源与管理事务配置类
db246
@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
@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;
}
}
六、测试效果
启动类
/**
* @author eddie.lee
*/
@SpringBootApplication
@EnableConfigurationProperties(value = {DbConfig246.class, DbConfig247.class})
public class XaDemoApplication {
public static void main(String[] args) {
SpringApplication.run(XaDemoApplication.class, args);
}
}
业务层
@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);
}
}
单元测试
@RunWith(SpringRunner.class)
@SpringBootTest
class XaDemoApplicationTests {
@Autowired
private XAService xaService;
@Test
void contextLoads() {
}
@Test
public void testXA() {
xaService.testXA();
}
}
- 第一次运行,插入成功
- 修改数据库"ALTER TABLE
xa_247
.xa_247
MODIFY COLUMNname
varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL AFTERid
" - 第二次运行,出现"### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column ‘name’ at row 1"的错误。
- 查看数据库,246与247也没有插入,证明已经成效了分布式事务
TIPS: Mycat 与 ShardingJdbc 默认已经开启XA事务管理