当前位置: 首页 > news >正文

在Spring Boot中使用JTA实现对多数据源的事务管理

了解事务的都知道,在我们日常开发中单单靠事务管理就可以解决绝大多数问题了,但是为啥还要提出JTA这个玩意呢,到底JTA是什么呢?他又是具体来解决啥问题的呢?

JTA

JTA(Java Transaction API)是Java平台上用于管理分布式事务的API。它提供了一组接口和类,用于协调和控制跨多个资源(如数据库、消息队列等)的事务操作

JTA的架构体系如下:
在这里插入图片描述

JTA的主要目标是确保分布式环境中的事务的原子性、一致性、隔离性和持久性(ACID属性)。它通过以下几个关键概念和组件来实现:

  • 事务管理器(Transaction Manager):负责协调和管理事务的开始、提交和回滚等操作。它是JTA的核心组件,负责跟踪和控制事务的状态。

  • 用户事务(User Transaction):表示应用程序发起的事务,通过事务管理器来管理和控制。

  • XA资源管理器(XA Resource Manager):表示分布式环境中的资源,如数据库、消息队列等。它实现了XA接口,可以参与到分布式事务中。

  • XA事务(XA Transaction):表示跨多个XA资源管理器的分布式事务。它遵循XA协议,通过两阶段提交(Two-Phase Commit)来保证事务的一致性。

使用JTA,开发人员可以在分布式环境中编写具有事务保证的应用程序。它提供了一种标准化的方式来处理分布式事务,简化了开发人员的工作,同时确保了数据的一致性和可靠性。
JTA事务比我们常用的JDBC事务更加强大,一个JTA事务可以有多个参与者,而一个JDBC事务则别限定在一个单一的数据库连接。

这么说吧,我举个栗子:

我们采用多数据源的时候,假设我们对A数据源的更新与B数据源的更新具有事务性,比如:我们对订单中创建一条新的订单数据,同时我也需要在商品库中进行相关商品的扣减库存,假设我们对库存进行扣减失败了,那么我们肯定希望我们的订单也返回到之前没下订单之前的状态,毕竟我下了订单了,库存没减少,我这算哪门子的下了订单。

如果这两条数据位于一个数据库,那么我们可以通过简单的事务管理就可以完成操作,那么我们至此就可以结束了,但是当我们的这两个操作要是在不同的数据库中,那么我们该怎么办呢?

那么我们就来测试一下:
Spring Boot中引入相关依赖:

		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!--重点围绕这个类--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jta-atomikos</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>

之后再Spring Boot application配置连接数据库的相关配置:

spring.jta.enabled=truespring.jta.atomikos.datasource.primary.xa-properties.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.jta.atomikos.datasource.primary.xa-properties.user=root
spring.jta.atomikos.datasource.primary.xa-properties.password=123456
spring.jta.atomikos.datasource.primary.xa-data-source-class-name=com.mysql.cj.jdbc.MysqlXADataSource
spring.jta.atomikos.datasource.primary.unique-resource-name=test1
spring.jta.atomikos.datasource.primary.max-pool-size=25
spring.jta.atomikos.datasource.primary.min-pool-size=3
spring.jta.atomikos.datasource.primary.max-lifetime=20000
spring.jta.atomikos.datasource.primary.borrow-connection-timeout=10000spring.jta.atomikos.datasource.secondary.xa-properties.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.jta.atomikos.datasource.secondary.xa-properties.user=root
spring.jta.atomikos.datasource.secondary.xa-properties.password=123456
spring.jta.atomikos.datasource.secondary.xa-data-source-class-name=com.mysql.cj.jdbc.MysqlXADataSource
spring.jta.atomikos.datasource.secondary.unique-resource-name=test2
spring.jta.atomikos.datasource.secondary.max-pool-size=25
spring.jta.atomikos.datasource.secondary.min-pool-size=3
spring.jta.atomikos.datasource.secondary.max-lifetime=20000
spring.jta.atomikos.datasource.secondary.borrow-connection-timeout=10000
@Configuration
public class DataSourceConfiguration {@Primary@Bean@ConfigurationProperties(prefix = "spring.jta.atomikos.datasource.primary")public DataSource primaryDataSource() {return new AtomikosDataSourceBean();}@Bean@ConfigurationProperties(prefix = "spring.jta.atomikos.datasource.secondary")public DataSource secondaryDataSource() {return new AtomikosDataSourceBean();}@Beanpublic JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource primaryDataSource) {return new JdbcTemplate(primaryDataSource);}@Beanpublic JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {return new JdbcTemplate(secondaryDataSource);}}

创建一个测试Service用来校验我们的JTA是否可以完成我们想要的工作。

@Service
public class TestService {private JdbcTemplate primaryJdbcTemplate;private JdbcTemplate secondaryJdbcTemplate;public TestService(JdbcTemplate primaryJdbcTemplate, JdbcTemplate secondaryJdbcTemplate) {this.primaryJdbcTemplate = primaryJdbcTemplate;this.secondaryJdbcTemplate = secondaryJdbcTemplate;}@Transactionalpublic void tx() {// 修改test1库中的数据primaryJdbcTemplate.update("update user set age = ? where name = ?", 30, "aaa");// 修改test2库中的数据secondaryJdbcTemplate.update("update user set age = ? where name = ?", 30, "aaa");}@Transactionalpublic void tx2() {// 修改test1库中的数据primaryJdbcTemplate.update("update user set age = ? where name = ?", 40, "aaa");// 模拟:修改test2库之前抛出异常throw new RuntimeException();}
}

在以上操作中,我们定义tx方法中,一般会成功,但tx2方法中,我们自己给他定义了一个异常,这个是在test1数据库更新后才会产生的,这样就可以测试一test1更新成功后,是否还能再JTA的帮助下实现回滚。

创建一个单元测试类:

@SpringBootTest(classes = Application.class)
public class ApplicationTests {@Autowiredprotected JdbcTemplate primaryJdbcTemplate;@Autowiredprotected JdbcTemplate secondaryJdbcTemplate;@Autowiredprivate TestService testService;@Testpublic void test1() throws Exception {// 正确更新的情况testService.tx();Assertions.assertEquals(30, primaryJdbcTemplate.queryForObject("select age from user where name=?", Integer.class, "aaa"));Assertions.assertEquals(30, secondaryJdbcTemplate.queryForObject("select age from user where name=?", Integer.class, "aaa"));}@Testpublic void test2() throws Exception {// 更新失败的情况try {testService.tx2();} catch (Exception e) {e.printStackTrace();} finally {// 部分更新失败,test1中的更新应该回滚Assertions.assertEquals(30, primaryJdbcTemplate.queryForObject("select age from user where name=?", Integer.class, "aaa"));Assertions.assertEquals(30, secondaryJdbcTemplate.queryForObject("select age from user where name=?", Integer.class, "aaa"));}}
}

对以上测试用例:

test1:因为没有故意制造的异常,一般情况下两个库的update都会成功,然后我们根据name=aaa去把两个数据查出来,看age是否都被更新到了30。

test2:tx2函数会把test1中name=aaa的用户age更新为40,然后抛出异常,JTA事务生效的话,会把age回滚回30,所以这里的检查也是两个库的aaa用户的age应该都为30,这样就意味着JTA事务生效,保证了test1和test2两个库中的User表数据更新一致,没有制造出脏数据。

相关文章:

在Spring Boot中使用JTA实现对多数据源的事务管理

了解事务的都知道&#xff0c;在我们日常开发中单单靠事务管理就可以解决绝大多数问题了&#xff0c;但是为啥还要提出JTA这个玩意呢&#xff0c;到底JTA是什么呢&#xff1f;他又是具体来解决啥问题的呢&#xff1f; JTA JTA&#xff08;Java Transaction API&#xff09;是…...

介绍YOLO-NAS Pose:姿势估计的技术

YOLO-NAS 姿势 YOLO-NAS Pose models是对 Pose Estimation 领域的最新贡献。今年早些时候,Deci 因其突破性的目标检测基础模型 YOLO-NAS 获得了广泛认可。在 YOLO-NAS 成功的基础上,该公司现在推出了 YOLO-NAS Pose 作为其姿势估计的对应产品。该姿势模型在延迟和准确性之间…...

计算机毕业设计 基于SpringBoot的实训管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…...

Python开发运维:Python3.7使用QQ邮箱发送不同类型邮件

目录 一、理论 1.邮件发送 二、实验 1.Python3.7使用QQ邮箱发送普通邮件 2.Python3.7使用QQ邮箱发送包含图片与附件的邮件 三、问题 1.Pycharm中如何放大和缩小代码界面 一、理论 1.邮件发送 &#xff08;1&#xff09;概念 SMTP&#xff08;Simple Mail Transfer Pro…...

二十三种设计模式全面解析-解密迭代器模式:探索遍历之道

在软件开发中&#xff0c;遍历数据集合是一个非常常见的需求。但是&#xff0c;如何以一种优雅、灵活的方式遍历集合&#xff0c;并且能够适应各种不同的数据结构和迭代方式&#xff0c;一直是开发者们面临的挑战。今天&#xff0c;我将带你深入探索迭代器模式&#xff08;Iter…...

kubernetes istio

目录 一、部署 二、部署示例应用 三、部署遥测组件 四、流量管理 五、熔断 官网&#xff1a;https://istio.io/latest/zh/about/service-mesh/ 一、部署 提前准备好文件 tar zxf 15t10-1.19.3-linux-amd64.tar.gz cd 15t10-1.19.3/ export PATH$PWD/bin:$PATHistioctl install …...

25期代码随想录算法训练营第十四天 | 二叉树 | 递归遍历、迭代遍历

目录 递归遍历前序遍历中序遍历后序遍历 迭代遍历前序遍历中序遍历后序遍历 递归遍历 前序遍历 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # …...

常用布局以及其优缺点

当涉及到设计和排版时&#xff0c;有许多不同的布局方式可供选择。以下是几种常见的布局方式以及它们的优缺点&#xff1a; 流式布局&#xff08;Fluid Layout&#xff09;&#xff1a; 优点&#xff1a;能够根据屏幕大小自动调整内容&#xff0c;适应不同设备。灵活性高&#…...

海康工业相机如何提高相机帧率

影响帧率的因素 相机参数 帧率限制使能 像素格式 曝光时间 数据包大小&#xff08;网口&#xff09; 相机默认参数 ADC位深 系统环境设置...

Linux之IPC通信共享内存(一次拷贝)与消息队列、管道、信号量、socket(两次拷贝)总结(六十二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…...

【多线程 - 01、概述】

进程 几乎所有的操作系统都支持进程概念&#xff0c;进程是处于运行过程中的程序&#xff0c;进程是操作系统中进行资源分配的基本单位。 三个基本特征 独立性&#xff1a;指进程实体是一个能独立运行、独立获得资源和独立接受调度的基本单位。而对于未建立任何进程的程序&…...

SQL SELECT INTO 语句

SQL SELECT INTO 语句 使用 SQL&#xff0c;您可以将信息从一个表中复制到另一个表中。 SELECT INTO 语句从一个表中复制数据&#xff0c;然后将数据插入到另一个新表中。 SQL SELECT INTO 语法 我们可以把所有的列都复制到新表中&#xff1a; SELECT * INTO newtable [IN ex…...

【刷题】(AtCoder Beginner Contest 328) C、D 补题

前言 第一次打 a了两道 C、D都是TLE 看了其他人的题解之后 有一些想法 所以发一篇博客 C 题干 题目链接 我的思路及做题过程 我的思路是 输入left、right 再在这个区间内计算字母相同的对数 代码是&#xff1a; #include<iostream> #include<cmath> #includ…...

NI USRP软件无线设备的特点

NI USRP软件无线设备 NI的USRP(Universal Software Radio Peripheral)设备是RF应用中使用的软件无线(SDR)。NI的USRP收发器可以在多个频段发送和接收RF信号&#xff0c;因此可用于通信工程教育和研究。通过与LabVIEW开发环境相结合&#xff0c;USRP可以实现使用无线信号验证无…...

大数据毕业设计选题推荐-污水处理大数据平台-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…...

最新获取支付宝cardIndex参数图文教程

本章教程主要介绍如何获取支付宝的cardIndex参数。 目录 一、登录到支付宝官网 二、在历史记录中,找到对应用户 一、登录到支付宝官网...

Linux学习第二枪(yum,vim,g++/gcc,makefile的使用)

前言&#xff1a;在我的上一篇Linux博客我已经讲了基础指令和权限&#xff0c;现在我们来学习如何在Linux上运行和执行代码 目录 一&#xff0c;yum 二&#xff0c;vim 1&#xff09;命令行模式 2&#xff09;插入模式 3&#xff09;底行模式 三&#xff0c;gcc/g 四&a…...

自然语言处理(一):RNN

「循环神经网络」&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一个非常经典的面向序列的模型&#xff0c;可以对自然语言句子或是其他时序信号进行建模。进一步讲&#xff0c;它只有一个物理RNN单元&#xff0c;但是这个RNN单元可以按照时间步骤进行展开…...

超全总结!大模型算法面试指南(含答案)

大家好&#xff0c;从 2019 年的谷歌 T5 到 OpenAI GPT 系列&#xff0c;参数量爆炸的大模型不断涌现。可以说&#xff0c;LLMs 的研究在学界和业界都得到了很大的推进&#xff0c;尤其去年 11 月底对话大模型 ChatGPT 的出现更是引起了社会各界的广泛关注。 近些年&#xff0…...

前端使用C-lodop 实现循环套打小案例

目录 前言引入js文件小案例 前言 lodop是一个很优秀打印插件&#xff0c;具体的大家可以官网了解&#xff0c;先在官网下载插件&#xff0c;安装在本地&#xff0c;并启动&#xff0c;点击官网下载 引入js文件 //本JS是加载Lodop插件或Web打印服务CLodop/Lodop7的综合示例&a…...

如何选择适合的西安GEO优化机构进行云造智搜AIGEO服务?

在选择适合的西安GEO优化机构时&#xff0c;了解其收费标准与服务内容构成至关重要。不同机构的费用结构可能各异&#xff0c;常见的费用包括基础服务费、项目管理费和根据效果而定的提成。在评估团队实力时&#xff0c;查看其过往案例和客户反馈是有效的方法&#xff0c;可帮助…...

【SPIE-电子科技大学主办】第三届计算机视觉、机器人与自动化工程国际学术会议(CRAE 2026)

第三届计算机视觉、机器人与自动化工程国际学术会议&#xff08;CRAE 2026&#xff09;将于2026年6月26-28日在成都举行。会议聚焦于计算机视觉、机器人与自动化工程等前沿研究领域&#xff0c;旨在为全球范围内的专家学者、工程技术人员和技术研发人员提供一个高效的平台。往届…...

为什么92%的AIAgent项目卡在世界建模阶段?深度拆解6个被忽略的感知-记忆-推理对齐断点

第一章&#xff1a;世界模型在AIAgent架构中的核心定位与失败率归因 2026奇点智能技术大会(https://ml-summit.org) 世界模型&#xff08;World Model&#xff09;并非AIAgent的可选组件&#xff0c;而是其认知闭环的底层基础设施——它承担着环境建模、状态推演、反事实规划与…...

学术是一场马拉松吗

最近录用一篇 EJOR&#xff0c;虽然是一件比较高兴的事&#xff0c;却没有那么的喜悦。因为根据我阅读多篇 EJOR 论文的经验&#xff0c;这篇投稿论文有 EJOR 的实力&#xff0c;即使被拒稿了&#xff0c;我会转投 COR 或者领域内其他不错的杂志&#xff0c;晚点发表而已。 目前…...

从X-Bogus到X-Gnarly:拆解TikTok Web端反爬策略的演进与对抗思路

从X-Bogus到X-Gnarly&#xff1a;TikTok Web端反爬策略的深度解析与应对策略 在当今数据驱动的互联网环境中&#xff0c;Web平台与数据采集者之间的攻防博弈从未停止。作为全球领先的短视频平台&#xff0c;TikTok在保护其数据安全方面投入了大量资源&#xff0c;构建了一套复杂…...

**基于Python的智慧医疗影像辅助诊断系统设计与实现**在智慧医疗快速发展的今天,医学影

基于Python的智慧医疗影像辅助诊断系统设计与实现 在智慧医疗快速发展的今天&#xff0c;医学影像已成为临床诊疗不可或缺的重要工具。然而&#xff0c;传统人工阅片效率低、易疲劳、漏诊率高&#xff0c;尤其面对海量CT/MRI数据时问题更加突出。本文将结合Python编程语言&…...

B 站超 5 亿播放、“高数救星”宋浩老师新作《微积分精选 850 题》终于来了!

大学有两大渡劫现场&#xff1a;一是早八占座&#xff0c;二是微积分考试。你是不是也这样&#xff1f;上课的时候跟着老师的思路走觉得&#xff1a;“哇好简单。”笔记记得密密麻麻。一到下课自己做题&#xff0c;看着题目突然大脑空白&#xff1a;“公式在哪来着&#xff1f;…...

C3D行为识别实战:UCF101视频数据预处理与帧提取全流程

1. 认识UCF101数据集与行为识别基础 第一次接触视频行为识别时&#xff0c;我对着UCF101数据集发了半天呆——这堆视频文件该怎么变成模型能理解的格式&#xff1f;后来才发现&#xff0c;预处理才是决定模型效果的关键第一步。UCF101作为行为识别领域的"MNIST"&…...

主题巴巴主题源码 合辑打包下载+主题巴巴SEO插件 _ WordPress主题模版

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示一、详细介绍 主题巴巴WordPress主题合辑打包下载&#xff0c;包含博客一号、博客二号、博客X、门户一号、门户手机版、图片一号、杂志一号、自媒体一号、自媒体二号和主题巴巴SEO插件。 主题巴巴WordPress主题合辑打…...

Rustup进阶指南:5个高效管理Rust工具链的实战技巧

Rustup进阶指南&#xff1a;5个高效管理Rust工具链的实战技巧 【免费下载链接】rustup The Rust toolchain installer 项目地址: https://gitcode.com/gh_mirrors/ru/rustup Rustup作为Rust官方工具链安装器&#xff0c;让开发者能够轻松管理多个Rust版本、切换发布渠道…...