Java分布式事务(九)
文章目录
- 🔥XA强一致性分布式事务实战_Atomikos介绍
- 🔥XA强一致性分布式事务实战_业务说明
- 🔥XA强一致性分布式事务实战_项目搭建
- 🔥XA强一致性分布式事务实战_多数据源实现
- 🔥XA强一致性分布式事务实战_业务层实现
🔥XA强一致性分布式事务实战_Atomikos介绍
简单介绍
Atomikos(https://www.atomikos.com/),其实是一家公司的名字,提供了基于 JTA规范的XA分布式事务TM的实现 。其旗下最著名的产品就是事务管理器。
产品分两个版本:
⭐TransactionEssentials:开源的免费产品;
⭐ExtremeTransactions:上商业版,需要收费。
这两个产品的关系如下图所示:
ExtremeTransactions 在 TransactionEssentials 的基础上额外提供了以下功能:
⭐支持 TCC:这是一种柔性事务
⭐支持通过 RMI、IIOP、SOAP 这些远程过程调用技术,进行事务传播。
⭐事务日志云存储,云端对事务进行恢复,并且提供了完善的管理后台。
什么是JTA
Java事务API(JTA:Java Transaction API)和它的同胞Java事务服务(JTS:Java Transaction Service),为J2EE平台提供了分布式事务服务(distributed transaction)的能力。
⭕
要想使用用 JTA 事务,那么就需要有一个实现
javax.sql.XADataSource 、 javax.sql.XAConnection 和javax.sql.XAResource 接口的 JDBC 驱动程序。
一个实现了这些接口的驱动程序将可以参与 JTA 事务。
一个 XADataSource 对象就是一个 XAConnection 对象的工厂。
XAConnection 是参与JTA 事务的 JDBC 连接。
🔥XA强一致性分布式事务实战_业务说明
场景介绍
本案例使用Atomikos框架实现XA强一致性分布式事务,模拟跨库转账的业务场景。不同账户之间的转账操作通过同一个项目程序完成。
说明:
转账服务不会直接连接数据库进行转账操作,而是通过Atomikos框架对数据库连接进行封装,通过Atomikos框架操作不同的数据库。由于Atomikos框架内部实现了XA分布式事务协议,因此转账服务的逻辑处理不用关心分布式事务是如何实现的,只需要关注具体的业务逻辑。
框架选型
框架名字 | 版本 |
---|---|
MySQL | 5.7 |
JDK | 1.8 |
微服务框架 | SpringBoot 2.6.3 |
分布式事务框架 | Atomikos |
持久层框架 | Mybatis plus |
user_account数据表结构
设计完数据表后,在192.168.66.100服务器创建2个数据库,分别为tx-xa-01和tx-xa-02,分别在2个数据库中创建转出金额数据库。
DROP TABLE IF EXISTS user_account;
CREATE TABLE user_account (account_no varchar(64) CHARACTER SET utf8
COLLATE utf8_bin NOT NULL COMMENT '账户编号'
,account_name varchar(64) CHARACTER SET utf8
COLLATE utf8_bin NULL DEFAULT NULL COMMENT '账户名称',account_balance decimal(10, 2) NULL DEFAULT
NULL COMMENT '账户余额',PRIMARY KEY (account_no) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE
= utf8_bin ROW_FORMAT = Dynamic;
添加数据
tx-xa-01库中添加数据。
INSERT INTO `user_account` VALUES ('1001',
'张三', 10000.00);
tx-xa-02库中添加数据。
INSERT INTO `user_account` VALUES ('1002',
'李四', 10000.00);
🔥XA强一致性分布式事务实战_项目搭建
创建atomikos-xa项目
创建依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starterweb</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starterjta-atomikos</artifactId></dependency><!-- druid连接池依赖组件--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-bootstarter</artifactId><version>1.1.22</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-bootstarter</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>
编写配置文件
server:port: 6003
spring:autoconfigure:#停用druid连接池的自动配置exclude:
com.alibaba.druid.spring.boot.autoconfigure.Dru
idDataSourceAutoConfiguredatasource:#选用druid的XADataSource数据源,因为这个数据源支
持分布式事务管理type:
com.alibaba.druid.pool.xa.DruidXADataSource#以下是自定义字段dynamic:primary: masterdatasource:master:url:
jdbc:mysql://192.168.66.102:3306/tx-xa-01?
useUnicode=true&characterEncoding=utf-
8&allowMultiQueries=true&useSSL=false&zeroDateT
imeBehavior=convertToNull&serverTimezone=Asia/S
hanghai&autoReconnect=trueusername: rootpassword: 123456driver-class-name:
com.mysql.jdbc.Driverslave:url:
jdbc:mysql://192.168.66.102:3306/tx-xa-02?
useUnicode=true&characterEncoding=utf-
8&allowMultiQueries=true&useSSL=false&zeroDateT
imeBehavior=convertToNull&serverTimezone=Asia/S
hanghai&autoReconnect=trueusername: rootpassword: 123456driver-class-name:
com.mysql.jdbc.Drivervalidation-query: SELCET 1
编写主启动类
@Slf4j
@SpringBootApplication
@EnableTransactionManagement(proxyTargetClass = true)
public class TxXaStarter {public static void main(String[] args){SpringApplication.run(TxXaStarter.class,args);log.info("*************** TxXaStarter
*********");}
}
🔥XA强一致性分布式事务实战_多数据源实现
创建第一个数据源的配置类DBConfig1
@Data
@ConfigurationProperties(prefix =
"spring.datasource.dynamic.datasource.master")
public class DBConfig1 {private String url;private String username;private String password;private String dataSourceClassName;
}
创建第二个数据源的配置类DBConfig2
@Data
@ConfigurationProperties(prefix =
"spring.datasource.dynamic.datasource.slave")
public class DBConfig2 {private String url;private String username;private String password;private String dataSourceClassName;
}
创建持久层接口
分别在com.it.mapper1包和com.it.mapper2包下
创建UserAccount1Mapper接口和UserAccount2Mapper接口。
public interface UserAccount1Mapper extends
BaseMapper<UserAccount> {
}
public interface UserAccount2Mapper extends
BaseMapper<UserAccount> {
}
创建MyBatisConfig1类
MyBatisConfig1类的作用是整合Atomikos框架,读取DBConfig1类中的信息,实现数据库连接池,最终通过Atomikos框架的数据库连接池连接数据库并操作。
@Configuration
@MapperScan(basePackages =
"com.it.mapper1", sqlSessionTemplateRef
= "masterSqlSessionTemplate")
public class MyBatisConfig1 {@Bean(name = "masterDataSource")public DataSource
masterDataSource(DBConfig1 dbConfig1) {AtomikosDataSourceBean sourceBean = new AtomikosDataSourceBean();sourceBean.setUniqueResourceName("masterDataSource");sourceBean.setXaDataSourceClassName(dbConfig1.getDataSourceClassName());sourceBean.setTestQuery("select 1");sourceBean.setBorrowConnectionTimeout(3);MysqlXADataSource dataSource = new
MysqlXADataSource();dataSource.setUser(dbConfig1.getUsername());dataSource.setPassword(dbConfig1.getPassword()
);dataSource.setUrl(dbConfig1.getUrl());sourceBean.setXaDataSource(dataSource);return sourceBean;}@Bean(name = "masterSqlSessionFactory")public SqlSessionFactory
masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception
{MybatisSqlSessionFactoryBean
sqlSessionFactoryBean = new
MybatisSqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource
);return
sqlSessionFactoryBean.getObject();}@Bean(name = "masterSqlSessionTemplate")public SqlSessionTemplate
masterSqlSessionTemplate(@Qualifier("masterSqlS
essionFactory") SqlSessionFactory
sqlSessionFactory){return new
SqlSessionTemplate(sqlSessionFactory);}
}
创建MyBatisConfig2类
MyBatisConfig2类的作用与MyBatisConfig1类的作用相似,只不过MyBatisConfig2类读取的是DBConfig2类中的信息,封装的是整合了Atomikos框架的另一个数据源的数据库连接池,通过连接池连接数据库并操作。
@Configuration
@MapperScan(basePackages =
"com.it.mapper2", sqlSessionTemplateRef
= "slaveSqlSessionTemplate")
public class MyBatisConfig2 {@Bean(name = "slaveDataSource")public DataSource slaveDataSource(DBConfig2 dbConfig2) {AtomikosDataSourceBean sourceBean = new AtomikosDataSourceBean();sourceBean.setUniqueResourceName("slaveDataSource");sourceBean.setXaDataSourceClassName(dbConfig2.
getDataSourceClassName());sourceBean.setTestQuery("select 1");sourceBean.setBorrowConnectionTimeout(3);MysqlXADataSource dataSource = new
MysqlXADataSource();dataSource.setUser(dbConfig2.getUsername());dataSource.setPassword(dbConfig2.getPassword()
);dataSource.setUrl(dbConfig2.getUrl());sourceBean.setXaDataSource(dataSource);return sourceBean;}@Bean(name = "slaveSqlSessionFactory")public SqlSessionFactory
slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource dataSource) throws Exception {MybatisSqlSessionFactoryBean
sqlSessionFactoryBean = new
MybatisSqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSoure
);return
sqlSessionFactoryBean.getObject();}@Bean(name = "slaveSqlSessionTemplate")public SqlSessionTemplate
slaveSqlSessionTemplate(@Qualifier("slaveSqlSessionFactory") SqlSessionFactory
sqlSessionFactory){return new
SqlSessionTemplate(sqlSessionFactory);}
}
🔥XA强一致性分布式事务实战_业务层实现
项目的业务逻辑层主要实现具体的跨库转账的业务逻辑,由于具体的XA跨库分布式事务是由Atomikos框架内部实现的,因此在业务逻辑层处理跨库转账的逻辑时,就像操作本地数据库一样简单。
创建UserAccount类
@Data
@TableName("user_account")
@AllArgsConstructor
@NoArgsConstructor
public class UserAccount implements
Serializable {private static final long serialVersionUID = 6909533252826367496L;/*** 账户编号*/@TableIdprivate String accountNo;/*** 账户名称*/private String accountName;/*** 账户余额*/private BigDecimal accountBalance;
}
创建UserAccountService接口
public interface UserAccountService {/*** 跨库转账* @param sourceAccountNo 转出账户* @param targetSourceNo 转入账户* @param bigDecimal 金额*/void transferAccounts(String sourceAccountNo, String targetSourceNo,
BigDecimal transferAmount);
}
实现UserAccountService接口
package com.it.service.impl;
import com.it.entity.UserAccount;
import com.it.mapper1.UserAccountMapper1;
import com.it.mapper2.UserAccountMapper2;
import com.it.service.IUserAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import
org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
/**
* <p>
* 服务实现类
* </p>
*
* @author itbaizhan
* @since 05-13
*/
@Service
public class UserAccountServiceImpl implements
IUserAccountService {@Autowiredprivate UserAccountMapper1
userAccountMapper1;@Autowiredprivate UserAccountMapper2
userAccountMapper2;/*** 跨库转账* @param sourceAccountNo 源账户* @param targetSourceNo 目标账户* @param bigDecimal 金额*/@Transactional@Overridepublic void transofer(String
sourceAccountNo, String targetSourceNo,
BigDecimal bigDecimal) {// 1. 查询原账户UserAccount sourceUserAccount =
userAccountMapper1.selectById(sourceAccountNo);// 2. 查询目标账户UserAccount targetUserAccount =
userAccountMapper2.selectById(targetSourceNo);// 3. 判断转入账户和转出账户是否为空if (sourceAccountNo != null &&
targetUserAccount != null){// 4. 判断转出账户是否余额不足if
(sourceUserAccount.getAccountBalance().compare To(bigDecimal) < 0){throw new RuntimeException("余额不足");}// 5.更新金额sourceUserAccount.setAccountBalance(sourceUserAccount.getAccountBalance().subtract(bigDecimal));// 6.张三账户减金额userAccountMapper1.updateById(sourceUserAccount);System.out.println(10/0);// 7.更新金额targetUserAccount.setAccountBalance(targetUserAccount.getAccountBalance().add(bigDecimal));// 8.张三账户减金额userAccountMapper2.updateById(targetUserAccount);}}
}
相关文章:

Java分布式事务(九)
文章目录🔥XA强一致性分布式事务实战_Atomikos介绍🔥XA强一致性分布式事务实战_业务说明🔥XA强一致性分布式事务实战_项目搭建🔥XA强一致性分布式事务实战_多数据源实现🔥XA强一致性分布式事务实战_业务层实现…...

基于深度学习的动物识别系统(YOLOv5清新界面版,Python代码)
摘要:动物识别系统用于识别和统计常见动物数量,通过深度学习技术检测日常几种动物图像识别,支持图片、视频和摄像头画面等形式。在介绍算法原理的同时,给出Python的实现代码、训练数据集以及PyQt的UI界面。动物识别系统主要用于常…...
K8S集群之-ETCD集群监控
### 生产ETCD集群监控核心指标 etcd服务存活状态 up{job~"kubernetes-etcd.*"}0 说明:up0代表服务挂掉 etcd是否有脱离情况 etcd_server_has_leader{job~"kubernetes-etcd.*"}0 说明:每个instance,该值应该都…...

一文弄懂熵、交叉熵和kl散度(相对熵)
一个系统中事件发生的概率越大,也就是其确定性越大,则其包含的信息量越少,可以认为一个事件的信息量就是该事件发生难度的度量,事件所包含的信息量越大则其发生的难度越大。并且相互独立的事件,信息量具有可加性。相互…...

10从零开始学Java之开发Java必备软件Intellij idea的安装配置与使用
作者:孙玉昌,昵称【一一哥】,另外【壹壹哥】也是我哦CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者前言壹哥在前面的文章中,带大家下载、安装、配置了Eclipse这个更好用的IDE开发工具,并教会了大家如何在Ecli…...

04 - 进程参数编程
---- 整理自狄泰软件唐佐林老师课程 查看所有文章链接:(更新中)Linux系统编程训练营 - 目录 文章目录1. 问题1.1 再论execve(...)1.2 main函数(默认进程入口)1.3 进程空间概要图1.4 编程实验:进程参数剖析1…...

【python进阶】你真的懂元组吗?不仅是“不可变的列表”
📚引言 🙋♂️作者简介:生鱼同学,大数据科学与技术专业硕士在读👨🎓,曾获得华为杯数学建模国家二等奖🏆,MathorCup 数学建模竞赛国家二等奖🏅,…...
《C++ Primer Plus》(第6版)第13章编程练习
《C Primer Plus》(第6版)第13章编程练习《C Primer Plus》(第6版)第13章编程练习1. Cd类2. 使用动态内存分配重做练习13. baseDMA、lacksDMA、hasDMA类4. Port类和VintagePort类《C Primer Plus》(第6版)第…...

【多线程】多线程案例
✨个人主页:bit me👇 ✨当前专栏:Java EE初阶👇 ✨每日一语:we can not judge the value of a moment until it becomes a memory. 目 录🍝一. 单例模式🍤1. 饿汉模式实现🦪2. 懒汉模…...

【IoT】嵌入式驱动开发:IIC子系统
IIC有三种接口实现方式 三种时序对比: 图1 IIC子系统组成 图2 图3 IIC操作流程 设备端 1.i2c_get_adapter 2.i2c_new_device(相当于register设备) 3.I2c_put_adapter 驱动端 1.填充i2c_driver 2.i2c_add_driver(相当于register驱动) 3.在probe中建立访问方式 client相…...

DJ2-4 进程同步(第一节课)
目录 2.4.1 进程同步的基本概念 1. 两种形式的制约关系 2. 临界资源(critical resource) 3. 生产者-消费者问题 4. 临界区(critical section) 5. 同步机制应遵循的规则 2.4.2 硬件同步机制 1. 关中断 2. Test-and-Set …...
AI独立开发者:一周涨粉8万赚2W美元;推特#HustleGPT GPT-4创业挑战;即刻#AIHackathon创业者在行动 | ShowMeAI周刊
👀日报&周刊合辑 | 🎡生产力工具与行业应用大全 | 🧡 点赞关注评论拜托啦! 这是ShowMeAI周刊的第7期。聚焦AI领域本周热点,及其在各圈层泛起的涟漪;拆解AI独立开发者的盈利案例,关注中美AIG…...

不要迷信 QUIC
很多人都在强调 QUIC 能解决 HoL blocking 问题,不好意思,我又要泼冷水了。假设大家都懂 QUIC,不再介绍 QUIC 的细节,直接说问题。 和 TCP 一样,QUIC 也是一个基于连接的,保序的可靠传输协议,T…...
【28】Verilog进阶 - RAM的实现
VL53 单端口RAM 1 思路 简简单单,读取存储器单元值操作即可 2 功能猜想版 说明: 下面注释就是我对模块端口信号 自己猜测的理解。 因为题目并没有说清楚,甚至连参考波形都没有给出。 唉,这就完全是让人猜测呢,如果一点学术背景的人来刷题,指定不容易!! 好在,我有较为…...

【MySQL】聚合查询
目录 1、前言 2、插入查询结果 3、聚合查询 3.1 聚合函数 3.1.1 count 3.1.2 sum 3.1.3 avg 3.1.4 max 和 min 4、GROUP BY 子句 5、HAVING 关键字 1、前言 前面的内容已经把基础的增删改查介绍的差不多了,也介绍了表的相关约束, 从本期开始…...

初时STM32单片机
目录 一、单片机基本认知 二、STM系列单片机命名规则 三、标准库与HAL库区别 四、通用输入输出端口GPIO 五、推挽输出与开漏输出 六、复位和时钟控制(RCC) 七、时钟控制 八、中断和事件 九、定时器介绍 一、单片机基本认知 单片机和PC电脑相比…...

debian部署docker(傻瓜式)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 debian10部署dockerdebian10部署docker(傻瓜式)一、准备工作二、**使用 APT 安装,注意要先配置apt网络源**1.配置网络源2.官方下载三、安装…...

JS判断是否为base64字符串如何转换为图片src格式
需求背景 : 如何判断后端给返回的 字符串 是否为 base-64 位 呢 ? 以及如果判断为是的话,如何给它进行转换为 img 标签可使用的那种 src 格式 呢 ? 1、判断字符串是否为 base64 以下方法,可自行挨个试试,…...

【SpringMVC】SpringMVC方式,向作用域对象共享数据(ModelAndView、Model、map、ModelMap)
个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ 向域对象共享数据一、使用 原生ServletAPI二、…...
本科课程【移动互联网应用开发(Android开发)】实验3 - Activity及数据存储
大家好,我是【1+1=王】, 热爱java的计算机(人工智能)渣硕研究生在读。 如果你也对java、人工智能等技术感兴趣,欢迎关注,抱团交流进大厂!!! Good better best, never let it rest, until good is better, and better best. 近期会把自己本科阶段的一些课程设计、实验报…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...