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

作者:帽子平头 时间:2022-08-29 19:45:47 

背景

我们平时在用springboot开发时,要使用事务,只需要在方法上添加@Transaction注解即可,但这种方式只适用单数据源,在多数据源下就不再适用;

比如在多数据源下,我们在一个方法里执行了数据源A的操作,又执行了数据源B的操作,如果报错了,事务只会回滚主数据源或者是指定事务的数据源数据(@Transactional(value="指定事务")),另一个数据源是不会回滚的;

这种情况下,单纯的@Transactional事务注解是无法实现的,此时就需要用到多数据源事务管理;

以下项目里实现了普通情况下的事务处理和使用springboot-jta-atomikos事务处理

本文主要介绍使用springboot-jta-atomikos来实现;

源码地址

https://github.com/lvlq73/springboot-jta-atomikos

项目目录结构

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

 实现

1.添加依赖 pom.xml

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

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=arsenal

spring.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 = "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 = "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表没有记录

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

数据库test2 user表没有记记录

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

来源:https://www.cnblogs.com/lvlq73/p/15991323.html

标签:springboot,多数据源,事务管理
0
投稿

猜你喜欢

  • 基于java枚举类综合应用的说明

    2023-02-16 09:39:25
  • SpringBoot整合Docker实现一次构建到处运行的操作方法

    2023-01-23 04:32:14
  • Spring Boot启动时调用自己的非web逻辑

    2022-02-15 11:40:10
  • @Value如何获取yml和properties配置参数

    2021-12-12 13:24:01
  • java集合迭代器Iterator中的remove陷阱

    2022-06-17 16:11:54
  • java发送kafka事务消息的实现方法

    2022-05-17 01:18:35
  • Android 使用FragmentTabhost代替Tabhost

    2021-09-10 19:10:26
  • 深入解析Java的Spring框架中的混合事务与bean的区分

    2021-12-28 19:48:41
  • 深入学习C#多线程

    2021-06-12 12:35:04
  • android 调用系统的照相机和图库实例详解

    2022-01-02 11:46:47
  • Java中遍历Map集合的5种方式总结

    2023-04-29 13:14:25
  • 解决EditText不显示光标的三种方法(总结)

    2023-09-19 08:05:10
  • SpringSceurity实现短信验证码登陆

    2023-06-23 00:37:35
  • 详解在idea 中使用Mybatis Generator逆向工程生成代码

    2023-09-09 17:05:24
  • 详解Android StrictMode严格模式的使用方法

    2023-09-14 17:03:39
  • Android图像切换器imageSwitcher的实例应用

    2023-10-06 00:30:56
  • SpringCloud微服务熔断器Hystrix使用详解

    2023-07-06 22:57:46
  • android中在Activity中响应ListView内部按钮的点击事件的两种方法

    2021-12-25 16:31:07
  • Android ListView ImageView实现单选按钮实例

    2023-09-19 20:25:39
  • Java 数据结构之删除链表中重复的结点

    2023-11-28 15:36:22
  • asp之家 软件编程 m.aspxhome.com