springboot-jta-atomikos多数据源事务管理
背景
我们平时在用springboot开发时,要使用事务,只需要在方法上添加@Transaction注解即可,但这种方式只适用单数据源,在多数据源下就不再适用;
比如在多数据源下,我们在一个方法里执行了数据源A的操作,又执行了数据源B的操作,如果报错了,事务只会回滚主数据源或者是指定事务的数据源数据(@Transactional(value="https://www.it610.com/article/指定事务")),另一个数据源是不会回滚的;
这种情况下,单纯的@Transactional事务注解是无法实现的,此时就需要用到多数据源事务管理;
以下项目里实现了普通情况下的事务处理和使用springboot-jta-atomikos事务处理
本文主要介绍使用springboot-jta-atomikos来实现;
项目目录结构
文章图片
实现
1.添加依赖 pom.xml
org.springframework.boot
spring-boot-starter-jta-atomikos
2.配置数据库连接信息 application.properties
#atomikos测试
spring.datasource.test1.url=jdbc:mysql://127.0.0.1:3306/test1?allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai
spring.datasource.test1.user=root
spring.datasource.test1.password=arsenalspring.datasource.test2.url=jdbc:mysql://127.0.0.1:3306/test2?allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai
spring.datasource.test2.user=root
spring.datasource.test2.password=arsenal
3.创建多数据源 DBAtomikosConfig.java
package com.llq.atomikos.config;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
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;
/**
* @author lvlianqi
* @description
* @date 2022/3/7
*/
@Configuration
public class DBAtomikosConfig {//--------------------数据源1--------------------
@ConfigurationProperties(prefix = "spring.datasource.test1")
@Bean
public Properties testOneProperties() {
return new Properties();
}@Bean(name = "testOneDataSource")
@Primary
public DataSource testOneDataSource() {
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
Properties prop = testOneProperties();
ds.setXaDataSourceClassName("com.mysql.cj.jdbc.MysqlXADataSource");
ds.setUniqueResourceName("testOne");
ds.setXaProperties(prop);
return ds;
}@Bean
@Primary
public JdbcTemplate testOneJdbcTemplate(@Qualifier("testOneDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}//--------------------数据源2--------------------
@ConfigurationProperties(prefix = "spring.datasource.test2")
@Bean
public Properties testTwoProperties() {
return new Properties();
}@Bean(name = "testTwoDataSource")
public DataSource testTwoDataSource() {
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
Properties prop = testTwoProperties();
ds.setXaDataSourceClassName("com.mysql.cj.jdbc.MysqlXADataSource");
ds.setUniqueResourceName("testTwo");
ds.setXaProperties(prop);
return ds;
}@Bean
public JdbcTemplate testTwoJdbcTemplate(@Qualifier("testTwoDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
//--------------------配置spring的JtaTransactionManager,底层委派给atomikos进行处理--------------------
@Bean
public JtaTransactionManager jtaTransactionManager () {
UserTransactionManager userTransactionManager = new UserTransactionManager();
UserTransaction userTransaction = new UserTransactionImp();
return new JtaTransactionManager(userTransaction, userTransactionManager);
}
}
4.测试事务类 TestAtomikos.java
package com.llq.atomikos.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author lvlianqi
* @description
* @date 2022/3/7
*/
@Service
public class TestAtomikos implements ITest{@Qualifier("testOneJdbcTemplate")
@Autowired
private JdbcTemplate testOneJdbcTemplate;
@Qualifier("testTwoJdbcTemplate")
@Autowired
private JdbcTemplate testTwoJdbcTemplate;
/**
* 测试正常情况
*/
@Transactional(rollbackFor = Exception.class, value = "https://www.it610.com/article/jtaTransactionManager")
public void test() {
testOneJdbcTemplate.execute("insert into user (name, age) values ('张三', 18);
");
testTwoJdbcTemplate.execute("insert into user (name, age) values ('李四', 20);
");
}/**
* 测试异常情况
*/
@Transactional(rollbackFor = Exception.class, value = "https://www.it610.com/article/jtaTransactionManager")
public void testByException() {
testOneJdbcTemplate.execute("insert into user (name, age) values ('张三', 18);
");
testTwoJdbcTemplate.execute("insert into user (name, age) values ('李四', 20);
");
int i = 1/0;
}
}
5.测试 SpringbootAtomikosApplicationTests.java
//使用atomikos
private static Class CLS = TestAtomikos.class;
@Autowired
ApplicationContext applicationContext;
@Test
public void testByException() {
ITest test = (ITest) applicationContext.getBean(CLS);
test.testByException();
}
测试结果 【springboot-jta-atomikos多数据源事务管理】执行错误

文章图片
数据库test1 user表没有记录

文章图片
数据库test2 user表没有记录

文章图片
推荐阅读
- (数据科学学习手札134)pyjanitor(为pandas补充更多功能)
- 使用JPA+querydsl如何实现多条件动态查询
- ⑦(多线程篇)、《史上最全iOS八股文面试题》2022年|⑦(多线程篇)、《史上最全iOS八股文面试题》2022年,金三银四我为你准备了,iOS《1000条》笔试题以及面试题
- YY|【C语言】三子棋游戏与多子棋 (保姆级的实现过程)
- modeller建模(单模板建模、多模板建模)
- 可作为工质状态参数的是_知到网课答案多元统计分析及R语言建模课后作业答案...
- 拓端tecdat|拓端tecdat|R语言多变量广义正交GARCH(GO-GARCH)模型对股市高维波动率时间序列拟合预测
- 拓端tecdat|拓端tecdat|Python多项式Logistic逻辑回归进行多类别分类和交叉验证准确度箱线图可视化
- 拓端数据tecdat|拓端tecdat|R语言数量生态学冗余分析RDA分析植物多样性物种数据结果可视化
- PTA|【PTA乙级】【1101 B是A的多少倍 (15 分)】