springboot-jta-atomikos多数据源事务管理实现
作者:帽子平头 发布时间:2022-08-29 19:45:47
标签:springboot,多数据源,事务管理
背景
我们平时在用springboot开发时,要使用事务,只需要在方法上添加@Transaction注解即可,但这种方式只适用单数据源,在多数据源下就不再适用;
比如在多数据源下,我们在一个方法里执行了数据源A的操作,又执行了数据源B的操作,如果报错了,事务只会回滚主数据源或者是指定事务的数据源数据(@Transactional(value="指定事务")),另一个数据源是不会回滚的;
这种情况下,单纯的@Transactional事务注解是无法实现的,此时就需要用到多数据源事务管理;
以下项目里实现了普通情况下的事务处理和使用springboot-jta-atomikos事务处理
本文主要介绍使用springboot-jta-atomikos来实现;
源码地址
https://github.com/lvlq73/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();
}
测试结果
执行错误
数据库test1 user表没有记录
数据库test2 user表没有记记录
来源:https://www.cnblogs.com/lvlq73/p/15991323.html


猜你喜欢
- 当数据库中存有大量数据的时候,用Cursor查询时要注意,有可能引发性能问题。数据库查询出来的Cursor都会由一个CursorWindow
- 一、什么是Spring Cloud?SpringCloud 对常见的分布式系统模式提供了简单易用的编程模型,帮助开发者构建弹性、可靠、协调的
- Spring Boot中可以在配置文件中直接进行数据库配置,spring.datasource.username= rootspring.d
- 原理和listview一样 ,都是重写Android原生控件Activitypackage com.example.refreshgridv
- 1.官方地址:http://mybatis.plus/guide/generator.html#%E4%BD%BF%E7%94%A8%E6%
- 最近在看 C++ 的方法重载,我就在想 C# 中的重载底层是怎么玩的,很多朋友应该知道 C 是不支持重载的,比如下面的代码就会报错。#inc
- 在用C#开发windows端程序并连接SQL Server时有可能会遇到数据库登录失败的问题,报错现象如下图所示:报错信息如下:System
- 对于yield关键字我们首先看一下msdn的解释:如果你在语句中使用 yield 关键字,则意味着它在其中出现的方法、运算符或 get 访问
- 蓝牙设置相关界面,以下是通过C#方式打开的几个方式,记录一下蓝牙设置界面1.控制面板命令bthprops.cpl可以用控制面板 contro
- 思路:首先进入登录界面,输入账号和密码后登陆到主界面,在主界面通过点击按钮发送一条强制下线的广播,广播接收者收到广播后重新进入登陆界面。新建
- 简介在Spring 5中,Spring MVC引入了webFlux的概念,webFlux的底层是基于reactor-netty来的,而rea
- 本文实例为大家分享了java二叉查找树的具体代码,供大家参考,具体内容如下package 查找;import edu.princeton.c
- 在网上很多关于dubbo异常统一处理的博文,90%都是抄来抄去。大多都是先上一段dubbo中对于异常的统一处理的原码,然后说一堆的(甚至有1
- 使用 DateFormat 格式化日期、时间DateFormat 也是一个抽象类,它也提供了如下几个类方法用于获取 DateFormat 对
- 前言本文将介绍通过Java编程在PDF文档中添加表格的方法。添加表格时,可设置表格边框、单元格对齐方式、单元格背景色、单元格合并、插入图片、
- 前言我们开始 Flutter 动画相关篇章之旅,在应用中通过动效能够给用户带来更愉悦的体验,比较典型的例子就是一些直播平台的动效了,比如送火
- 今天给大家分享纯注解版spring与mybatis的整合mybatis包下:有这几个,上面图片没有展开配置Bean:MyBatisAutoC
- 当目标数据库不能直连的,需要一个服务器作为中间跳板的时候,我们需要通过SSH通道连接数据库。ps:使用ssh连接,相当于本地开了个端口去连接
- 自然排序TreeSet集合在存储数据时有一定的顺序,它会将一些数据进行比较,比较调用的是comparaTo()方法,该方法是在Compara
- 可以使用 Java 8 中的 Map.replaceAll() 方法将所有的值转为 String 类型:Map<String, Obj