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

[Java实战]Spring Boot整合Seata:分布式事务一致性解决方案(三十一)

[Java实战]Spring Boot整合Seata:分布式事务一致性解决方案(三十一)

引言

在微服务架构中,业务逻辑被拆分为多个独立的服务,每个服务可能拥有独立的数据库。当需要跨服务操作多个数据库时,如何保证数据的一致性成为关键挑战。Seata(Simple Extensible Autonomous Transaction Architecture)是阿里开源的分布式事务解决方案,支持AT、TCC、SAGA等多种事务模式。本文以 AT模式 为例,结合Spring Boot,讲解如何实现分布式事务的强一致性。

一、分布式事务与Seata原理
1.1 分布式事务的挑战
  • CAP理论:在分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition Tolerance)无法同时满足。
  • BASE理论:通过牺牲强一致性,实现最终一致性(Basically Available, Soft state, Eventually consistent)。
1.2 Seata的核心概念
  • TC(Transaction Coordinator):事务协调器,负责全局事务的提交或回滚。
  • TM(Transaction Manager):事务管理器,定义全局事务的边界(如@GlobalTransactional)。
  • RM(Resource Manager):资源管理器,管理分支事务的资源(如数据库连接)。
1.3 AT模式工作原理
  1. 阶段一(提交预操作)
    • TM向TC注册全局事务。
    • RM执行SQL操作,生成前置镜像(before image)和后置镜像(after image),并记录undo_log。
  2. 阶段二(提交或回滚)
    • 全局事务成功:TC异步删除undo_log。
    • 全局事务失败:TC根据undo_log反向补偿数据。
二、环境准备
2.1 依赖组件
  • Seata Server:1.5.0+
  • 注册中心:Nacos(或其他支持的服务发现组件)
  • 数据库:MySQL(需支持undo_log表)
2.2 数据库表准备

在每个业务数据库中添加 undo_log 表:

CREATE TABLE `undo_log` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`branch_id` bigint(20) NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int(11) NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

三、Docker部署Nacos与Seata Server
3.1 部署Nacos

使用Docker快速启动Nacos服务:

# 拉取Nacos镜像(以2.0.3版本为例)
docker pull docker.1ms.run/nacos/nacos-server:v2.0.3# 启动Nacos容器(单机模式)
docker run -d \--name nacos-server \-p 8848:8848 \-e MODE=standalone \  # 单机模式-e JVM_XMS=256m \    # 最小内存-e JVM_XMX=256m \    # 最大内存--restart=always \docker.1ms.run/nacos/nacos-server:v2.0.3#整合执行  docker run -d --name nacos-server -p 8848:8848 -e MODE=standalone -e JVM_XMS=256m -e JVM_XMX=256m --restart=always docker.1ms.run/nacos/nacos-server:v2.0.3

验证访问:浏览器打开 http://localhost:8848/nacos,默认账号/密码:nacos/nacos

3.2 部署Seata Server

拉取Seata镜像并启动容器:

# 拉取Seata镜像(以1.5.0版本为例)
docker pull docker.1ms.run/seataio/seata-server:1.5.0# 启动Seata Server容器
docker run -d \--name seata-server \-p 8091:8091 \        # Seata TC端口-p 7091:7091 \        # Seata控制台端口(可选)-e SEATA_IP=宿主机IP \  # 需替换为实际IP(用于微服务连接)-e SEATA_CONFIG_NAME=file:/seata-server/resources/registry \--restart=always \docker.1ms.run/seataio/seata-server:1.5.0#整合一行方便执行docker run -d --name seata-server -p 8091:8091 -p 7091:7091 -e SEATA_IP=192.168.231.132 -e SEATA_CONFIG_NAME=file:/seata-server/resources/registry --restart=always docker.1ms.run/seataio/seata-server:1.5.0
3.3 Docker Compose一键部署 (可选)

创建 docker-compose.yml

version: '3'
services:nacos-server:image: nacos/nacos-server:v2.0.3ports:- "8848:8848"environment:- MODE=standalonenetworks:- seata-netseata-server:image: seataio/seata-server:1.5.0ports:- "8091:8091"- "7091:7091"environment:- SEATA_IP=宿主机IPvolumes:- ~/seata/config:/seata-server/resourcesnetworks:- seata-netdepends_on:- nacos-servernetworks:seata-net:driver: bridge

启动命令:

docker-compose up -d
3.4 关键配置挂载(可选)

若需自定义Seata配置(如注册中心),可通过挂载配置文件:

  1. 创建本地目录 ~/seata/config,放入 registry.conf
registry {type = "nacos"nacos {application = "seata-server"serverAddr = "宿主机IP:8848"  # 替换为Nacos容器IP或宿主机IPnamespace = "public"cluster = "default"}
}config {type = "nacos"nacos {serverAddr = "宿主机IP:8848"namespace = "public"group = "SEATA_GROUP"}
}
  1. 启动容器时挂载配置:
docker run -d \... \-v ~/seata/config:/seata-server/resources \seataio/seata-server:1.5.0
四、Spring Boot项目配置
4.1 修改微服务配置

application.yml 中,确保Seata和Nacos指向Docker容器地址:

seata:application-id: order-service    # 服务名tx-service-group: my_tx_group    # 事务组名(需与Seata Server配置一致)service:vgroup-mapping:my_tx_group: default         # 事务组映射到Seata集群registry:type: nacos                    # 注册中心类型nacos:server-addr: 192.168.231.132:8848namespace: publicconfig:type: nacosnacos:server-addr: 192.168.231.132:8848group: SEATA_GROUPnamespace: public
4.2 确保容器间网络互通

若微服务也在Docker中运行,建议使用自定义网络:

# 创建自定义网络
docker network create seata-net# 启动容器时加入网络
docker run -d --network seata-net --name nacos-server ... 
docker run -d --network seata-net --name seata-server ... 

此时,微服务容器可通过容器名(如 nacos-server:8848)访问Nacos和Seata。

五、业务代码与测试

业务代码(如全局事务注解 @GlobalTransactional)无需修改,与本地部署完全一致。测试步骤参考原文档,重点关注以下验证点:

  1. 服务注册验证
  • 在Nacos控制台查看 order-serviceseata-server 是否注册成功。
  1. 事务回滚验证
  • 模拟账户扣款异常,检查订单、库存数据是否回滚。
  1. 日志排查
    • 查看Seata Server容器日志:
      docker logs -f seata-server
      
六、Spring Boot整合Seata
6.1 项目结构
distributed-transaction-demo
├── order-service       # 订单服务
├── storage-service     # 库存服务
└── account-service     # 账户服务
6.2 添加依赖

在父工程或各子模块的 pom.xml 中添加依赖:

<!-- Seata Starter -->
<dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>1.5.0</version>
</dependency>
<!-- Nacos Discovery -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>3.1.3</version> <!-- 使用与你的 Spring Cloud 版本兼容的版本 -->
</dependency>
6.3 配置Seata

application.yml 中配置Seata:

seata:application-id: order-service    # 服务名tx-service-group: my_tx_group    # 事务组名(需与Seata Server配置一致)service:vgroup-mapping:my_tx_group: default         # 事务组映射到Seata集群registry:type: nacos                    # 注册中心类型nacos:server-addr: 192.168.231.132:8848namespace: publicconfig:type: nacosnacos:server-addr: 192.168.231.132:8848group: SEATA_GROUPnamespace: public
6.5 业务代码实现

以订单服务为例,实现分布式事务:

@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate StorageFeignClient storageFeignClient;@Autowiredprivate AccountFeignClient accountFeignClient;@GlobalTransactional  // 开启全局事务public void createOrder(Order order) {// 1. 扣减库存storageFeignClient.deduct(order.getProductId(), order.getCount());// 2. 创建订单orderMapper.insert(order);// 3. 扣减账户余额accountFeignClient.deduct(order.getUserId(), order.getMoney());}
}
七、测试步骤
7.1 启动服务
  1. 启动 NacosSeata Server
  2. 依次启动 account-servicestorage-serviceorder-service
7.2 正常场景测试

使用Postman调用订单服务接口:

POST http://localhost:8080/order/create
Body:
{"userId": 1,"productId": 1,"count": 10,"money": 100
}

预期结果:订单创建成功,库存和账户余额均扣减。

7.3 异常场景测试

accountService.deduct() 方法中模拟异常:

public void deduct(Long userId, BigDecimal money) {// 模拟异常if (userId == 1) {throw new RuntimeException("账户扣款失败!");}// 正常扣款逻辑...
}

预期结果:订单未创建,库存扣减回滚,实现数据一致性。

八、常见问题与解决方案
  1. Seata Server无法连接Nacos

    • 检查Nacos地址和命名空间配置。
    • 确保Nacos中已配置 service.vgroupMapping
  2. undo_log表未生成

    • 检查数据库连接配置。
    • 确保每个业务库都执行了 undo_log.sql
  3. 事务未回滚

    • 确认方法上添加了 @GlobalTransactional
    • 检查异常是否被捕获(需抛出RuntimeException)。
九、总结

通过Seata的AT模式,Spring Boot可以轻松实现分布式事务的强一致性。核心步骤包括配置Seata Server、添加undo_log表、使用 @GlobalTransactional 注解标记全局事务。实际应用中需根据业务场景选择合适的事务模式(如TCC适用于高并发场景)。

附录
  • Seata官方文档

希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!

相关文章:

[Java实战]Spring Boot整合Seata:分布式事务一致性解决方案(三十一)

[Java实战]Spring Boot整合Seata&#xff1a;分布式事务一致性解决方案&#xff08;三十一&#xff09; 引言 在微服务架构中&#xff0c;业务逻辑被拆分为多个独立的服务&#xff0c;每个服务可能拥有独立的数据库。当需要跨服务操作多个数据库时&#xff0c;如何保证数据的…...

Openwrt下使用ffmpeg配合自建RTSP服务器实现推流

目前在Openwrt下时mjpg_streamer实现UVC摄像头转网络摄像头的方案很多&#xff0c;这种方案视频服在路由模组中&#xff0c;在局域网中使用很方便。但是对于需要远程监控管理的情况&#xff0c;mjpg_streamer不适应&#xff0c;因为不在局域网中的播放器无法访问到路由模组中的…...

MySQL 索引的增删改查

MySQL 索引的增删改查 1 建表时创建索引 [UNIQUE|FULLTEXT|SPATIAL] INDEX|KEY [别名] (字段名 [(长度)] [ASC|DESC] )主键直接写&#xff1a; PRIMARY KEY (Id)例如&#xff1a; CREATE TABLE people (id int NOT NULL PRIMARY KEY AUTO_INCREMENT,last_name varchar(10)…...

MySQL Host 被封锁解决方案(全版本适用 + Java 后端优化)

引言 MySQL 中 “Host is blocked because of many connection errors” 是生产环境常见问题&#xff0c;若处理不当会导致服务中断。本文结合 MySQL 官方文档&#xff08;5.5/8.0&#xff09;、Java 后端最佳实践及企业级经验&#xff0c;提供从 “快速解封” 到 “根源优化”…...

wifi 如果检查失败,UI 就会出现延迟或缺失打勾的现象。

问题&#xff1a;connectedSsid 的初始化依赖 onCreate 中的状态检查&#xff0c;如果检查失败&#xff0c;UI 就会出现延迟或缺失打勾的现象。 WIFI界面上上的一个标识代表成功连接。重启后出现偶尔不打勾的情况。 原始代码&#xff1a; // if (connectedSsid !…...

点云(point cloud):自动驾驶的“三维扫描图“

点云&#xff08;Point Cloud&#xff09;&#xff1a;就是用很多“点”来表示一个物体或场景的三维形状和结构。&#xff08;用点描绘的3D画&#xff0c;好比素描&#xff0c;但不是用线条勾勒&#xff0c;而是“点点点点”拼出物体形状&#xff09; 观察这幅图像&#xff0c;…...

Redis 中如何保证缓存与数据库的数据一致性?

在 Redis 中保证缓存与数据库的数据一致性是一个关键问题&#xff0c;尤其是在高并发环境下。由于缓存和数据库是两个独立的数据存储系统&#xff0c;它们之间的数据同步存在延迟和不确定性&#xff0c;因此需要采取一系列策略来保证数据的一致性。以下是几种常用的方法和策略&…...

Oracle RAC节点时间差异同步测试

前言&#xff1a; Oracle Real Application Clusters (RAC) 集群依赖于各节点间的心跳检测与缓存融合等机制&#xff0c;这些机制对节点间的时钟同步性有极高的要求。如果集群内不同节点之间存在显著的时间偏差&#xff0c;可能会导致整个集群运行异常。在较早版本的RAC中&…...

python 打卡DAY27

##注入所需库 import pandas as pd import seaborn as sns import matplotlib.pyplot as plt import random import numpy as np import time import shap # from sklearn.svm import SVC #支持向量机分类器 # # from sklearn.neighbors import KNeighborsClassifier …...

位运算及其算法

计算机中的所有数在内存中都是以二进制形式进行存储的 &#xff0c;位运算就是直接对整数二进制位进行操作&#xff0c;有些时候在程序中使用位运算进行操作&#xff0c;会得到极高的便利性。 有符号整数与无符号整数 我们以int整型为例&#xff0c;每个int占4个字节32个bit位…...

flutter getx路由管理、状态管理、路由守卫中间件、永久储存get_storage

一个简单的路由跳转、状态管理 目录 lib/ ├── main.dart ├── routes/index.dart // 路由表 ├── middlewares/auth_middleware.dart // 登录守卫 ├── pages/ │ ├── home_page.dart │ ├── login_page.dart │ └── profile_page.dart └─…...

贪心算法之跳跃游戏问题

问题背景 本文背景是leetcode的一道经典题目&#xff1a;跳跃游戏&#xff0c;描述如下&#xff1a; 给定一个非负整数数组 nums&#xff0c;初始位于数组的第一个位置&#xff08;下标0&#xff09;。数组中的每个元素表示在该位置可以跳跃的最大长度。判断是否能够到达最后…...

Dockers Compose常用指令介绍

Dockers Compose常用指令 1、常用指令介绍 1.1、version 指令 顶级一级指令&#xff0c;指定 compose 指定文件格式版本 version: "3.8" services: 不同版本支持的功能不同。常用版本有 ‘2’, ‘3’, ‘3.8’ 等。 1.2、services 指令 顶级一级指令&#xff0…...

YOLOv11 性能评估与横向对比

在第二章中&#xff0c;我们深入剖析了 YOLOv11 的核心技术&#xff0c;从骨干网络、颈部网络到头部&#xff0c;再到损失函数、数据增强和训练策略的创新&#xff0c;揭示了其高性能背后的奥秘。然而&#xff0c;理论的强大最终需要通过严谨的实验数据来验证。本章将详细阐述 …...

kafka在线增加分区副本数

1、问题来源 线上有一个物联网项目依赖kafka集群中指定主题消费&#xff0c;前些天kafka集群中的某一台机器出现了故障&#xff0c;导致kafka这个主题的数据一直无法消费&#xff0c;经查发现为了保证消息的顺序性此主题仅设置了一个分区&#xff0c;但是副本也仅有一个&#…...

Unity 如何使用Timeline预览、播放特效

在使用unity制作和拟合动画时&#xff0c;我们常用到Timeline&#xff0c;前后拖动滑轨&#xff0c;预览动画正放倒放非常方便。如果我们想对特效也进行这个操作&#xff0c;可以使用下文的步骤。 至此&#xff0c;恭喜你又解锁了一个新的技巧。如果我的分享对你有帮助&#xf…...

GIM发布新版本了 (附rust CLI制作brew bottle流程)

GIM 发布新版本了&#xff01;现在1.3.0版本可用了 可以通过brew upgrade git-intelligence-message升级。 初次安装需要先执行 brew tap davelet/gim GIM 是一个根据git仓库内文件变更自动生成git提交消息的命令行工具&#xff0c;参考前文《GIM: 根据代码变更自动生成git提交…...

GitHub 趋势日报 (2025年05月21日)

本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1microsoft/WSLLinux的Windows子系统⭐ 1731⭐ 25184C2virattt/ai-hedge-fundA…...

MySQL篇-其他面试题

MySQL事务 问题&#xff1a;事务是什么&#xff1f;ACID问题 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位&#xff0c;事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失败。 1、事务…...

iOS 蓝牙开发中的 BT 与 BLE

在 iOS 开发者的语境里&#xff0c;大家把 BT 和 BLE 当成两种不同的蓝牙技术在谈——它们来自同一个 Bluetooth 规范&#xff0c;但面向的场景、协议栈乃至 Apple 提供的 API 都截然不同。 缩写全称 / 技术名称规范层叫法iOS 支持现状典型用途BTBluetooth Classic&#xff08…...

Git的工作区,暂存区,本地仓库

Git 核心概念解析 1. 工作区&#xff08;Working Directory&#xff09; - 日常操作代码的目录&#xff0c;包含项目所有文件和子目录 - 开发者直接编辑和修改文件的位置 - 实际可见的项目文件结构 2. 暂存区&#xff08;Staging Area&#xff09; - 临时保存修改记录的缓冲区…...

鸿蒙Flutter实战:21-混合开发详解-1-概述

引言 在前面的系列文章中&#xff0c;我们从搭建开发环境开始&#xff0c;讲到如何使用、集成第三方插件&#xff0c;如何将现有项目进行鸿蒙化改造&#xff0c;以及上架审核等内容&#xff1b;还以高德地图的 HarmonyOS SDK 的使用为例&#xff0c; 讲解了如何将高德地图集成…...

MySQL错误1419(HY000)解决方案:SUPER权限缺失与二进制日志启用冲突的3种处理方式

一、错误背景与原因分析 错误描述 在执行存储过程、函数或触发器时,MySQL可能抛出以下错误: ERROR 1419 (HY000): You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)…...

[架构之美]从PDMan一键生成数据库设计文档:Word导出全流程详解(二十)

[架构之美]从PDMan一键生成数据库设计文档&#xff1a;Word导出全流程详解&#xff08;二十&#xff09; 一、痛点 你是否经历过这些场景&#xff1f; 数据库字段频繁变更&#xff0c;维护文档耗时费力用Excel维护表结构&#xff0c;版本混乱难以追溯手动编写Word文档&#…...

大量程粗糙度轮廓仪适用于哪些材质和表面?

大量程粗糙度轮廓仪是一种能够在广泛的测量范围内对工件表面进行粗糙度分析的精密仪器。它通常采用接触式或非接触式传感器&#xff0c;通过对工件表面的扫描&#xff0c;捕捉表面微观的起伏和波动&#xff0c;从而获取粗糙度数据。该仪器不仅能测量微小的表面细节&#xff0c;…...

linux 查看java的安装路径

一、验证Java安装状态 java -version正常安装会显示版本信息&#xff1a; openjdk version "1.8.0_65" OpenJDK Runtime Environment (build 1.8.0_65-b17) OpenJDK 64-Bit Server VM (build 25.65-b01, mixed mode)二、检查环境变量配置 若已配置JAVA_HOME&#…...

C 语言程序终止的艺术:理解 return main 与 exit() 函数

各类资料学习合集下载地址: ​​​​https://pan.quark.cn/s/472bbdfcd014​​ 每个 C 语言程序都有其起点——​​main​​ 函数。同样,每个程序也都有其终点,即程序执行完毕并退出。在 C 语言中,主要有两种方式可以优雅或立即地终止整个程序的执行,并将一个状态码传递给…...

数据实时同步:inotify + rsync 实现数据实时同步

1 数据实时同步 在生产环境中&#xff0c;某些场景下&#xff0c;要将数据或文件进行实时同步&#xff0c;保证数据更新后其它节点能立即获得最新的数据。 数据同步的两种方式 PULL&#xff1a;拉&#xff0c;使用定时任务的方式配合同步命令或脚本等&#xff0c;从指定服务…...

LeetCode 404.左叶子之和的迭代求解:栈结构与父节点定位的深度解析

一、题目解析&#xff1a;左叶子的定义与问题本质 题目描述 LeetCode 404. 左叶子之和要求计算二叉树中所有左叶子节点的值之和。左叶子的定义是&#xff1a;如果一个节点是其父节点的左子节点&#xff0c;并且它本身没有左右子节点&#xff0c;则称为左叶子。 关键要点 左…...

Unity-编辑器扩展

之前我们关于Unity的讨论都是针对于Unity底层的内容或者是代码层面的东西&#xff0c;这一次我们来专门研究Unity可视化的编辑器&#xff0c;在已有的基础上做一些扩展。 基本功能 首先我们来认识三个文件夹&#xff1a; Editor&#xff0c;Gizmos&#xff0c;Editor Defaul…...