springboot-jta-atomikos多数据源事务管理

背景 我们平时在用springboot开发时,要使用事务,只需要在方法上添加@Transaction注解即可,但这种方式只适用单数据源,在多数据源下就不再适用;
比如在多数据源下,我们在一个方法里执行了数据源A的操作,又执行了数据源B的操作,如果报错了,事务只会回滚主数据源或者是指定事务的数据源数据(@Transactional(value="https://www.it610.com/article/指定事务")),另一个数据源是不会回滚的;
这种情况下,单纯的@Transactional事务注解是无法实现的,此时就需要用到多数据源事务管理;
以下项目里实现了普通情况下的事务处理和使用springboot-jta-atomikos事务处理
本文主要介绍使用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多数据源事务管理】执行错误
springboot-jta-atomikos多数据源事务管理
文章图片

数据库test1 user表没有记录
springboot-jta-atomikos多数据源事务管理
文章图片

数据库test2 user表没有记录
springboot-jta-atomikos多数据源事务管理
文章图片

    推荐阅读