Java分布式事务(九)
创始人
2025-05-31 03:41:12

文章目录

    • 🔥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分布式事务协议,因此转账服务的逻辑处理不用关心分布式事务是如何实现的,只需要关注具体的业务逻辑。

框架选型

框架名字版本
MySQL5.7
JDK1.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项目
在这里插入图片描述

创建依赖

    org.springframework.bootspring-boot-starterweborg.springframework.bootspring-boot-starterjta-atomikoscom.alibabadruid-spring-bootstarter1.1.22mysqlmysql-connector-javacom.baomidoumybatis-plus-bootstarterorg.projectlomboklombok   

编写配置文件

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 {
}
public interface UserAccount2Mapper extends
BaseMapper {
}

创建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;
/**
* 

* 服务实现类 *

* * @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);}} }

相关内容

热门资讯

【实验报告】实验一 图像的... 实验目的熟悉Matlab图像运算的基础——矩阵运算;熟悉图像矩阵的显示方法࿰...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
大模型落地比趋势更重要,NLP... 全球很多人都开始相信,以ChatGPT为代表的大模型,将带来一场NLP领...
Linux学习之端口、网络协议... 端口:设备与外界通讯交流的出口 网络协议:   网络协议是指计算机通信网...
kuernetes 资源对象分... 文章目录1. pod 状态1.1 容器启动错误类型1.2 ImagePullBackOff 错误1....
STM32实战项目-数码管 程序实现功能: 1、上电后,数码管间隔50ms计数; 2、...
TM1638和TM1639差异... TM1638和TM1639差异说明 ✨本文不涉及具体的单片机代码驱动内容,值针对芯...
Qt+MySql开发笔记:Qt... 若该文为原创文章,转载请注明原文出处 本文章博客地址:https://h...
Java内存模型中的happe... 第29讲 | Java内存模型中的happen-before是什么? Java 语言...
《扬帆优配》算力概念股大爆发,... 3月22日,9股封单金额超亿元,工业富联、鸿博股份、鹏鼎控股分别为3.0...
CF1763D Valid B... CF1763D Valid Bitonic Permutations 题目大意 拱形排列࿰...
SQL语法 DDL、DML、D... 文章目录1 SQL通用语法2 SQL分类3 DDL 数据定义语言3.1 数据库操作3.2 表操作3....
文心一言 VS ChatGPT... 3月16号,百度正式发布了『文心一言』,这是国内公司第一次发布类Chat...
CentOS8提高篇5:磁盘分...        首先需要在虚拟机中模拟添加一块新的硬盘设备,然后进行分区、格式化、挂载等...
Linux防火墙——SNAT、... 目录 NAT 一、SNAT策略及作用 1、概述 SNAT应用环境 SNAT原理 SNAT转换前提条...
部署+使用集群的算力跑CPU密... 我先在开头做一个总结,表达我最终要做的事情和最终环境是如何的,然后我会一...
Uploadifive 批量文... Uploadifive 批量文件上传_uploadifive 多个上传按钮_asing1elife的...
C++入门语法基础 文章目录:1. 什么是C++2. 命名空间2.1 域的概念2.2 命名...
2023年全国DAMA-CDG... DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义...
php实现助记词转TRX,ET... TRX助记词转地址网上都是Java,js或其他语言开发的示例,一个简单的...
【分割数据集操作集锦】毕设记录 1. 按要求将CSV文件转成json文件 有时候一些网络模型的源码会有data.json这样的文件里...
Postman接口测试之断言 如果你看文字部分还是不太理解的话,可以看看这个视频,详细介绍postma...
前端学习第三阶段-第4章 jQ... 4-1 jQuery介绍及常用API导读 01-jQuery入门导读 02-JavaScri...
4、linux初级——Linu... 目录 一、用CRT连接开发板 1、安装CRT调试工具 2、连接开发板 3、开机后ctrl+c...
Urban Radiance ... Urban Radiance Fields:城市辐射场 摘要:这项工作的目标是根据扫描...
天干地支(Java) 题目描述 古代中国使用天干地支来记录当前的年份。 天干一共有十个,分别为:...
SpringBoot雪花ID长... Long类型精度丢失 最近项目中使用雪花ID作为主键,雪花ID是19位Long类型数...
对JSP文件的理解 JSP是java程序。(JSP本质还是一个Servlet) JSP是&#...
【03173】2021年4月高... 一、单向填空题1、大量应用软件开发工具,开始于A、20世纪70年代B、20世纪 80年...
LeetCode5.最长回文子... 目录题目链接题目分析解题思路暴力中心向两边拓展搜索 题目链接 链接 题目分析 简单来说࿰...