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

分布式事务的Java实践

文章目录

    • 概要
    • 整体架构流程
    • 技术名词解释
      • 微服务
      • 分布式事务
      • Seata
    • 技术细节
      • 前提
      • 整体机制
      • 写隔离
      • 理解
    • 基于spingcloud框架的seata导入
      • 部署seata环境
      • Seata AT模式
      • Seata配置文件
      • nacos配置示例
      • maven项目配置,
      • 测试验证
    • 参考

概要

随着市场发展,微服务架构已成为不可或缺的产物,单体架构已无法满足市场需求,比如一个软件公司,财务,考勤,人事管理,招聘面试,项目管理,资材管理等,是需要多个系统共同经营的,那就需要多个不同类型的数据库数据管理。不可避免的出现系统之间的数据传输和一致性保障,分布式事务应运而生。

整体架构流程

  • 这是一个微服务架构图
    架构图
    事务管理这块,除了MySQL自身支持事务外,MongoDB通过主副本集来管理事务,Seata扮演更重要的角色,就是多数据源的事务控制。

技术名词解释

微服务

微服务是一种软件架构风格,将单一应用程序拆分为多个小型、独立的服务。每个服务运行在独立的进程中,通过轻量级通信机制(如HTTP/REST或消息队列)协作,可独立开发、部署和扩展。核心特点包括松耦合、按业务能力划分、技术栈灵活及容错性强。

分布式事务

分布式事务指跨多个服务或数据库的事务操作,需保证所有参与方数据的一致性(ACID特性)。挑战在于网络延迟、节点故障等导致的协调复杂度。常见解决方案包括两阶段提交(2PC)、补偿事务(TCC)、本地消息表及Saga模式。

Seata

Seata(Simple Extensible Autonomous Transaction Architecture)是阿里开源的分布式事务中间件,支持AT(自动补偿)、TCC、Saga和XA模式。其核心模块包括事务协调器(TC)、资源管理器(RM)和应用(TM),通过全局事务ID实现跨服务事务管理,简化了分布式系统的数据一致性保证。

三者关联:微服务架构中,Seata为分布式事务提供标准化解决方案,确保跨服务调用时的数据一致性。

技术细节

这里重点说一下Seata的AT模式

前提

基于支持本地 ACID 事务的关系型数据库。
Java 应用,通过 JDBC 访问数据库。

整体机制

两阶段提交协议的演变:

  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。

  • 二阶段:
    提交异步化,非常快速地完成。
    回滚通过一阶段的回滚日志进行反向补偿。

写隔离

  • 一阶段本地事务提交前,需要确保先拿到 全局锁
  • 拿不到 全局锁 ,不能提交本地事务。
  • 拿到 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。

理解

这是官网给的原理,概括来说,就是执行事务之前,在数据库中存一份回滚记录,如果抛异常触发回滚,就从数据库中拿到回滚记录更新回去,若事务提交成功,则删掉,这里面还有全局锁用到全局事务ID在里面保障事务的原子性。

基于spingcloud框架的seata导入

部署seata环境

  • 这里直接用最方便的docker构建容器
docker run -d --restart always --name seata2-server -p 28091:28091 -p 27091:27091 -v /home/seata2/config:/seata-server/resources m.daocloud.io/docker.io/seataio/seata-server:2.0.0

Seata AT模式

  • 需要的maven项目数据库新建如下表
CREATE TABLE `undo_log` (`id` bigint NOT NULL AUTO_INCREMENT,`branch_id` bigint NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3520 DEFAULT CHARSET=utf8mb3;
  • Seata容器建表
CREATE TABLE `branch_table` (`branch_id` bigint NOT NULL,`xid` varchar(128) NOT NULL,`transaction_id` bigint DEFAULT NULL,`resource_group_id` varchar(32) DEFAULT NULL,`resource_id` varchar(256) DEFAULT NULL,`branch_type` varchar(8) DEFAULT NULL,`status` tinyint DEFAULT NULL,`client_id` varchar(64) DEFAULT NULL,`application_data` varchar(2000) DEFAULT NULL,`gmt_create` datetime(6) DEFAULT NULL,`gmt_modified` datetime(6) DEFAULT NULL,PRIMARY KEY (`branch_id`),KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;CREATE TABLE `distributed_lock` (`lock_key` char(20) NOT NULL,`lock_value` varchar(20) NOT NULL,`expire` bigint DEFAULT NULL,PRIMARY KEY (`lock_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;CREATE TABLE `global_table` (`xid` varchar(128) NOT NULL,`transaction_id` bigint DEFAULT NULL,`status` tinyint NOT NULL,`application_id` varchar(32) DEFAULT NULL,`transaction_service_group` varchar(32) DEFAULT NULL,`transaction_name` varchar(128) DEFAULT NULL,`timeout` int DEFAULT NULL,`begin_time` bigint DEFAULT NULL,`application_data` varchar(2000) DEFAULT NULL,`gmt_create` datetime DEFAULT NULL,`gmt_modified` datetime DEFAULT NULL,PRIMARY KEY (`xid`),KEY `idx_status_gmt_modified` (`status`,`gmt_modified`),KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;CREATE TABLE `lock_table` (`row_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,`xid` varchar(128) DEFAULT NULL,`transaction_id` bigint DEFAULT NULL,`branch_id` bigint NOT NULL,`resource_id` varchar(256) DEFAULT NULL,`table_name` varchar(100) DEFAULT NULL,`pk` varchar(36) DEFAULT NULL,`status` tinyint NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',`gmt_create` datetime DEFAULT NULL,`gmt_modified` datetime DEFAULT NULL,PRIMARY KEY (`row_key`),KEY `idx_status` (`status`),KEY `idx_branch_id` (`branch_id`),KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

Seata配置文件

#  Copyright 1999-2019 Seata.io Group.
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.server:port: 27091spring:application:name: seata-serverlogging:config: classpath:logback-spring.xmlfile:path: ${log.home:${user.home}/logs/seata} #日志路径extend:logstash-appender:destination: 127.0.0.1:4560kafka-appender:bootstrap-servers: 127.0.0.1:9092topic: logback_to_logstash
## 账号密码
console:user:username: seata123456password: seata123456
seata:config:# support: nacos, consul, apollo, zk, etcd3type: nacosnacos:server-addr: 192.168.x.xxx:8848  # nacos的ip端口group: SEATA2_GROUP        # 对应的组,默认为DEFAULT_GROUPusername: nacospassword: nacosdata-id: seataServer.properties # nacos中存放seata的配置文件,后面会提该文件的使用方式,相当于seata服务启动的时候需要注册到nacos,并使用nacos中的配置文件registry:# support: nacos, eureka, redis, zk, consul, etcd3, sofatype: nacosnacos:application: ${spring.application.name}server-addr: 192.168.x.xxx:8848group: SEATA2_GROUPcluster: defaultusername: nacospassword: nacosstore:# support: file 、 db 、 redis 、 raftmode: dbserver:service-port: 28091 #If not configured, the default is '${server.port} + 1000'security:secretKey: SeataSecretKeyxxxxxxxxtokenValidityInMilliseconds: 1800000ignore:urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login,/metadata/v1/**

nacos配置示例

# 数据存储方式,db代表数据库
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://xxx
store.db.user=xxx
store.db.password=xxx
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
# 事务、日志等配置
server.recovery.committingRetryPeriod=3000
server.recovery.asynCommittingRetryPeriod=3000
server.recovery.rollbackingRetryPeriod=3000
server.recovery.timeoutRetryPeriod=3000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000# 客户端与服务端传输方式
transport.serialization=seata
transport.compressor=none
# 关闭metrics功能,提高性能
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

maven项目配置,

  • 多个maven可以共用如下配置
seata:enabled: trueenable-auto-data-source-proxy: false # 多数据源需要设置enable-auto-data-source-proxy为falseapplication-id: ${spring.application.name} # Seata 应用编号,默认为 ${spring.application.name}tx-service-group: group1 # Seata 事务组编号,用于 TC 集群名# 服务配置项,对应 ServiceProperties 类service:# 虚拟组和分组的映射vgroup-mapping:group1: default# 分组和 Seata 服务的映射grouplist:default: 192.168.x.xxx:28091

测试验证

@GetMapping("/transactionTest")
@ApiOperation("事务测试")
@Transactional
public Result transactionTest(@RequestParam Integer num, @RequestParam Integer isError){//这里seataTestDao更新的本地MySQL数据库SeataTest seataTest = seataTestDao.selectById(1);seataTest.setNum(seataTest.getNum()+num);seataTestDao.updateById(seataTest);//这里feignService通过feigin调用接口更新另外一个容器数据库SeataTest2 seataTest2 = feignService.getSeataTest2ById(1);seataTest2.setNum(seataTest2.getNum()+num);feignService.updateSeataTest2ById(seataTest2);if(isError == 1){throw new RunTimeException();}return Result.ok();
}
  • 通过测试,查看对应表,验证事务生效。

参考

  • Seate官网AT模式

文章转载自:

http://Ab3WvCLh.nxstj.cn
http://FxNL9Kpz.nxstj.cn
http://5LcQC40Q.nxstj.cn
http://wCfoywsz.nxstj.cn
http://3sNTzoeL.nxstj.cn
http://rr5gETEI.nxstj.cn
http://1bpsOM8H.nxstj.cn
http://pI0zhbvj.nxstj.cn
http://OoTcbpIf.nxstj.cn
http://szTPb29Z.nxstj.cn
http://hBn5PcMA.nxstj.cn
http://g8dULhOV.nxstj.cn
http://16LljmnP.nxstj.cn
http://KnnWTm09.nxstj.cn
http://JL2g0U13.nxstj.cn
http://7IL7VzmO.nxstj.cn
http://4P6jYZxz.nxstj.cn
http://r2XhpbpU.nxstj.cn
http://p48CMAAi.nxstj.cn
http://dLjd4AGc.nxstj.cn
http://L9ZA9qbr.nxstj.cn
http://VSKT9EIo.nxstj.cn
http://A9ZxHRIx.nxstj.cn
http://D6Zp8BMH.nxstj.cn
http://OBTRou5D.nxstj.cn
http://T5hD04N8.nxstj.cn
http://L90wc52T.nxstj.cn
http://3KKTTnwT.nxstj.cn
http://yp5cMEiY.nxstj.cn
http://oHd4ePkh.nxstj.cn
http://www.dtcms.com/a/369119.html

相关文章:

  • 精准定位性能瓶颈:深入解析 PaddleOCR v3.2 全新 Benchmark 功能
  • The Algorithmic Foundations of Differential Privacy - 3(2)
  • 亚马逊关键词选择:从人工试错到智能闭环的进化之路
  • WIN11控制面板中丢失BitLocker,找回WIN10控制面板中的BitLocker驱动器加密设置
  • TDengine 时间函数 TODAY() 用户手册
  • 架构性能优化三板斧:从10秒响应到毫秒级的演进之路
  • LeetCode_位运算
  • 每日一算:颜色分类
  • 使用自定义固定公网URL地址远程访问公司内网OA办公系统,本地无需公网IP和专线让外网访问
  • pthread_join函数
  • 视觉项目,怎么选主机
  • AI生成内容的版权问题解析与实操指南
  • Oracle软件在主机平台的应用(课程下载)
  • TVS防护静电二极管选型需要注意哪些参数?-ASIM阿赛姆
  • 数据传输优化-异步不阻塞处理增强首屏体验
  • 通信安全员【单选题】考试题库及答案
  • 【开题答辩全过程】以 基于springboot的职业学校教务管理系统设计与实现为例,包含答辩的问题和答案
  • ImmutableMap
  • Oracle 10g → Oracle 19c 升级后问题解决方案(Pro*C 项目)
  • 使用MS-SWIF框架对大模型进行SFT微调
  • 使用PyTorch构建卷积神经网络(CNN)实现CIFAR-10图像分类
  • 非靶向模型中毒攻击和靶向模型中毒攻击
  • 步步高S9:AI重塑学习体验,定义智能教育新范式
  • 与优秀者同行,“复制经验”是成功的最快捷径
  • 2025 IT行业含金量超高的8大证书推荐
  • 《Keil 开发避坑指南:STM32 头文件加载异常与 RTE 配置问题全解决》
  • 基于STM32设计的激光充电控制系统(华为云IOT)_277
  • Kubernetes(四):Service
  • Android studio 既想拍照又想拿到Bitmap
  • 自由泳动作分解与技巧详解