SpringCloud进阶篇②:分布式事务(Seata)实操(解决跨服务数据一致性)
大家好,上一篇我们完成了微服务容器化部署(Docker+Compose),通过镜像打包和一键编排,彻底解决了“部署繁琐、环境不一致”的痛点,让微服务集群具备了可落地的部署能力。但在微服务实际运行中,还有一个致命痛点的未解决——跨服务数据一致性:比如“下单扣积分”场景,order-service成功创建订单,但user-service扣减积分时失败(服务宕机、网络异常),会导致“订单已创建、积分未扣减”的脏数据;再比如“下单扣库存”,订单创建成功但库存扣减失败,会导致超卖问题。今天就聚焦这个核心痛点,手把手教大家集成Seata实现分布式事务,解决跨服务数据不一致问题,全程实操、新手友好,跟着走就能掌握!
温馨提示:实操前请确认前提(避免踩坑):
① 已完成前10篇实操,微服务已实现Docker+Compose容器化部署,所有服务能正常通信;
② 版本保持一致:Spring Boot 2.6.13 + Spring Cloud Hoxton.SR12 + Nacos 2.0.7 + Seata 1.5.2(与Spring Boot 2.6.x兼容,新手必选此版本);
③ 已安装MySQL(用于Seata持久化和微服务业务数据);
④ 重点注意:本次实操基于Seata最易上手的AT模式,无需修改大量业务代码,仅需添加依赖、配置和注解;
⑤ 建议提前备份微服务代码和数据库数据(避免实操中数据混乱)。
一、先搞懂:分布式事务,微服务落地的必跨门槛
前10篇我们实现的微服务通信(OpenFeign),本质是“跨服务的远程调用”,每个微服务都有自己独立的数据库(比如order-service操作订单库,user-service操作用户库),这就导致了“分布式事务”问题——传统的本地事务(@Transactional)只能保证单个微服务内的数据一致性,无法覆盖跨服务的多个数据库操作。
核心痛点:跨服务数据不一致案例(新手直观理解)
我们以“下单扣积分”为实操场景(贴合前序微服务业务),模拟无分布式事务时的脏数据问题:
-
业务流程:用户发起下单请求 → gateway转发到order-service → order-service创建订单(操作订单库) → order-service通过Feign调用user-service → user-service扣减用户积分(操作用户库);
-
异常场景:order-service成功创建订单(本地事务提交,订单库数据已更新),但调用user-service时出现网络异常/服务宕机,导致user-service扣减积分失败(本地事务回滚,用户库数据未更新);
-
最终结果:订单已创建、积分未扣减,形成脏数据,违背业务逻辑,若不解决,会导致用户重复享受积分、系统数据混乱,严重影响业务正常运行。
类似的场景还有很多:下单扣库存、支付回调同步订单状态、转账业务等,只要涉及“跨服务、多数据库操作”,就会存在分布式事务问题。而Seata正是解决这个问题的主流方案,专为微服务分布式事务设计,简单易用、性能优异。
核心概念拆解(新手必记,避免混淆,拒绝复杂术语)
Seata的核心设计非常简单,核心分为3个角色,记住“1个协调者+多个参与者”的逻辑即可:
-
事务协调器(TC,Transaction Coordinator):独立的Seata服务端,核心职责是“协调所有参与者”——记录全局事务状态、发送提交/回滚指令,确保所有参与者要么一起提交,要么一起回滚;
-
事务管理器(TM,Transaction Manager):发起全局事务的微服务(比如本次场景中的order-service,因为它是第一个执行操作、并调用其他服务的入口),核心职责是“开启全局事务、通知TC提交/回滚”;
-
资源管理器(RM,Resource Manager):参与全局事务的所有微服务(比如本次场景中的order-service、user-service),核心职责是“执行本地事务、接收TC的指令、执行提交/回滚”;
补充:Seata AT模式核心原理(新手无需深入源码,记住结论即可):
AT模式是Seata默认、最常用的模式,无需手动编写回滚逻辑,核心分为两步:① 执行阶段:各微服务执行本地事务,记录数据修改前的快照(undo_log表),提交本地事务,释放锁;② 提交/回滚阶段:若所有微服务执行成功,TC通知所有RM提交(删除undo_log快照);若有一个微服务失败,TC通知所有RM回滚(根据undo_log快照恢复数据)。
补充:为什么选择Seata AT模式?(新手必看)
-
无侵入性:无需修改业务代码,仅需添加注解(@GlobalTransactional)和配置,新手易上手;
-
性能优异:执行阶段提交本地事务,释放锁,避免长时间锁表,适配高并发场景;
-
兼容性好:与Spring Cloud、Nacos、MySQL无缝兼容,贴合我们前10篇的微服务体系;
-
成熟稳定:阿里开源,广泛应用于生产环境,解决微服务分布式事务的主流方案。
二、实操核心:Seata AT模式实现分布式事务(下单扣积分场景)
本篇实操完全贴合前序微服务场景,以“order-service创建订单+user-service扣减积分”为核心,分为四大模块、9个核心步骤,从Seata服务端搭建到微服务集成,再到效果测试,全程落地:
模块一:环境准备(2步)→ 模块二:搭建Seata服务端(TC)(2步)→ 模块三:微服务集成Seata客户端(3步)→ 模块四:测试分布式事务效果(2步)
重点说明:
① 本次实操基于Docker+Compose部署Seata服务端,也可本地部署(新手任选);
② 核心是实现“订单创建”和“积分扣减”的原子性——要么都成功,要么都失败;
③ 所有配置均贴合之前的微服务版本,避免版本冲突。
三、模块一:环境准备(核心前提,必做)
3.1 第一步:创建Seata所需数据库和表
Seata服务端(TC)需要数据库存储全局事务信息,同时所有参与分布式事务的微服务(RM)需要创建undo_log表(用于数据回滚快照),步骤如下:
-
新建数据库(用于Seata服务端):在MySQL中创建数据库,命名为seata_db(自定义,便于记忆);
-
执行Seata初始化SQL(创建全局事务表):复制以下SQL到MySQL执行(适配Seata 1.5.2版本):
-- 全局事务表(Seata服务端使用)
CREATE TABLE IF NOT EXISTS `global_table` (
`xid` VARCHAR(128) NOT NULL COMMENT '全局事务ID',
`transaction_id` BIGINT NULL DEFAULT NULL COMMENT '事务ID',
`status` TINYINT NOT NULL COMMENT '状态:0-未提交,1-提交中,2-已提交,3-回滚中,4-已回滚',
`application_id` VARCHAR(32) NULL DEFAULT NULL COMMENT '应用ID',
`transaction_service_group` VARCHAR(32) NULL DEFAULT NULL COMMENT '事务组名称',
`transaction_name` VARCHAR(128) NULL DEFAULT NULL COMMENT '事务名称',
`timeout` INT NULL DEFAULT NULL COMMENT '超时时间',
`begin_time` BIGINT NULL DEFAULT NULL COMMENT '开始时间',
`application_data` VARCHAR(2000) NULL DEFAULT NULL COMMENT '应用数据',
`gmt_create` DATETIME NULL DEFAULT NULL COMMENT '创建时间',
`gmt_modified` DATETIME NULL DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`xid`),
INDEX `idx_gmt_modified_status` (`gmt_modified`, `status`),
INDEX `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='全局事务表';
-- 分支事务表(Seata服务端使用)
CREATE TABLE IF NOT EXISTS `branch_table` (
`branch_id` BIGINT NOT NULL COMMENT '分支事务ID',
`xid` VARCHAR(128) NOT NULL COMMENT '全局事务ID',
`transaction_id` BIGINT NULL DEFAULT NULL COMMENT '事务ID',
`resource_group_id` VARCHAR(32) NULL DEFAULT NULL COMMENT '资源组ID',
`resource_id` VARCHAR(256) NULL DEFAULT NULL COMMENT '资源ID',
`branch_type` VARCHAR(8) NULL DEFAULT NULL COMMENT '分支类型',
`status` TINYINT NOT NULL COMMENT '状态:0-未提交,1-提交中,2-已提交,3-回滚中,4-已回滚',
`client_id` VARCHAR(64) NULL DEFAULT NULL COMMENT '客户端ID',
`application_data` VARCHAR(2000) NULL DEFAULT NULL COMMENT '应用数据',
`gmt_create` DATETIME NULL DEFAULT NULL COMMENT '创建时间',
`gmt_modified` DATETIME NULL DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`branch_id`),
INDEX `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分支事务表';
-- 锁表(Seata服务端使用)
CREATE TABLE IF NOT EXISTS `lock_table` (
`row_key` VARCHAR(128) NOT NULL COMMENT '行锁键',
`xid` VARCHAR(128) NULL DEFAULT NULL COMMENT '全局事务ID',
`transaction_id` BIGINT NULL DEFAULT NULL COMMENT '事务ID',
`branch_id` BIGINT NOT NULL COMMENT '分支事务ID',
`resource_id` VARCHAR(256) NULL DEFAULT NULL COMMENT '资源ID',
`table_name` VARCHAR(32) NULL DEFAULT NULL COMMENT '表名',
`pk` VARCHAR(36) NULL DEFAULT NULL COMMENT '主键',
`gmt_create` DATETIME NULL DEFAULT NULL COMMENT '创建时间',
`gmt_modified` DATETIME NULL DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`row_key`),
INDEX `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='锁表';
- 给微服务数据库创建undo_log表:分别在order-service(订单库)、user-service(用户库)中执行以下SQL(RM回滚快照表):
-- undo_log表(所有参与分布式事务的微服务数据库都需要创建)
CREATE TABLE IF NOT EXISTS `undo_log` (
`branch_id` BIGINT NOT NULL COMMENT '分支事务ID',
`xid` VARCHAR(128) NOT NULL COMMENT '全局事务ID',
`context` VARCHAR(128) NOT NULL COMMENT '上下文信息',
`rollback_info` LONGBLOB NOT NULL COMMENT '回滚信息(快照)',
`log_status` INT NOT NULL COMMENT '日志状态:0-正常,1-已清理',
`log_created` DATETIME NOT NULL COMMENT '创建时间',
`log_modified` DATETIME NOT NULL COMMENT '修改时间',
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`),
INDEX `idx_log_created` (`log_created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='回滚快照表';
3.2 第二步:配置Nacos,添加Seata配置(核心,实现服务发现)
Seata服务端(TC)需要注册到Nacos,微服务(TM/RM)也需要从Nacos获取Seata的地址,步骤如下:
-
打开Nacos控制台(http://localhost:8848/nacos),切换到dev命名空间、DEV_GROUP分组;
-
点击“配置管理→配置列表→+”,创建Seata的全局配置,配置信息如下:
-
数据ID:seata-server-dev.yml(命名规范:服务名-环境.yml);
-
分组:DEV_GROUP(和微服务分组一致);
-
配置格式:YAML;
-
配置内容(复制粘贴,修改MySQL地址/用户名/密码为自己的):
# Seata服务端配置(TC)
server:
port: 8091 # Seata服务端默认端口
spring:
application:
name: seata-server
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: dev
group: DEV_GROUP
username: nacos
password: nacos
# Seata核心配置
seata:
# 事务组配置(核心,所有微服务需和此事务组一致)
tx-service-group: springcloud-seata-group
# 注册中心配置(Nacos)
registry:
type: nacos
nacos:
server-addr: localhost:8848
namespace: dev
group: DEV_GROUP
application: seata-server
username: nacos
password: nacos
# 配置中心配置(Nacos)
config:
type: nacos
nacos:
server-addr: localhost:8848
namespace: dev
group: DEV_GROUP
username: nacos
password: nacos
# 存储配置(MySQL,用于存储全局事务信息)
store:
mode: db # 存储模式:db(数据库),file(本地文件,不适合生产)
db:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/seata_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
user: root # 自己的MySQL用户名
password: 123456 # 自己的MySQL密码
min-conn: 5
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
query-limit: 100
max-wait: 5000
- 点击“发布”,Seata的Nacos配置生效;
易错点提醒:
① MySQL地址、用户名、密码必须修改为自己的,否则Seata服务端无法连接数据库;
② 事务组名称(springcloud-seata-group)后续微服务配置需和此一致,否则无法加入全局事务。
四、模块二:搭建Seata服务端(TC,事务协调器)
我们采用Docker+Compose部署Seata服务端(贴合上一篇容器化风格,一键启动,新手无需手动配置Seata环境),步骤如下:
4.1 第一步:修改Docker Compose配置,添加Seata服务
打开上一篇编写的docker-compose.yml文件,在services节点下添加Seata服务(放在Nacos服务之后,其他服务之前):
# 新增:Seata服务端(TC)
seata-server:
image: seataio/seata-server:1.5.2 # Seata版本1.5.2,与Spring Boot 2.6.x兼容
container_name: seata-server
ports:
- "8091:8091" # Seata默认端口
environment:
- SEATA_CONFIG_NAME=file:/root/seata-config/seata-server-dev.yml
- SEATA_IP=localhost # 本地部署,填写localhost即可
volumes:
# 挂载Nacos中Seata的配置文件(映射到容器内)
- ./seata-config:/root/seata-config
depends_on:
- nacos # 依赖Nacos,Nacos启动后再启动Seata
networks:
- springcloud-network
restart: always
4.2 第二步:启动Seata服务,验证部署成功
- 准备Seata配置文件挂载目录:在
docker-compose.yml同级目录新建seata-config文件夹,将Nacos中seata-server-dev.yml的配置内容复制,在该文件夹下新建seata-server-dev.yml文件,粘贴配置(确保容器能挂载到配置); - 进入
docker-compose.yml所在目录,执行启动命令(一键启动Seata和其他服务):
# 后台启动所有服务(若已启动,执行此命令会重启新增的Seata服务)
docker compose up -d
- 验证Seata启动成功:
-
查看容器状态:执行
docker compose ps,确保seata-server状态为Up; -
查看Nacos服务列表:访问Nacos控制台,服务列表中能看到
seata-server,状态为“UP”; -
查看Seata日志:执行
docker logs seata-server,无报错,显示“started successfully”,说明启动成功。
易错点提醒:
① Seata版本必须是1.5.2,与Spring Boot 2.6.x兼容,版本不匹配会导致微服务无法连接Seata;
② 配置文件挂载路径必须正确,否则Seata无法读取配置,启动失败。
五、模块三:微服务集成Seata客户端(TM+RM)
本次场景中,order-service是TM(发起全局事务),order-service和user-service都是RM(参与全局事务),gateway-service无需集成(不参与数据库操作),步骤如下(重点配置order和user服务):
5.1 第一步:给微服务添加Seata依赖(pom.xml)
分别给order-service和user-service添加Seata依赖(版本1.5.2,与Seata服务端一致),添加到dependencies标签内:
<!-- Seata客户端依赖 -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.5.2</version>
</dependency>
<!-- Seata与Nacos集成依赖(用于从Nacos获取Seata地址) -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-discovery-nacos</artifactId>
<version>1.5.2</version>
</dependency>
<!-- Seata与MySQL集成依赖(用于undo_log表操作) -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-rm-datasource</artifactId>
<version>1.5.2</version>
</dependency>
5.2 第二步:修改微服务Nacos配置,添加Seata客户端配置
分别在order-service-dev.yml和user-service-dev.yml中添加Seata客户端配置(放在配置末尾,复制粘贴即可,无需修改):
# Seata客户端配置(TM/RM)
seata:
# 事务组名称,必须和Seata服务端的事务组一致
tx-service-group: springcloud-seata-group
# 服务发现配置(从Nacos获取Seata服务端地址)
discovery:
type: nacos
nacos:
server-addr: localhost:8848
namespace: dev
group: DEV_GROUP
application: seata-server
username: nacos
password: nacos
# 配置中心配置(从Nacos获取Seata配置)
config:
type: nacos
nacos:
server-addr: localhost:8848
namespace: dev
group: DEV_GROUP
username: nacos
password: nacos
# 数据源代理配置(开启Seata数据源代理,用于生成undo_log快照)
datasource:
proxy-mode: AT # 采用AT模式
易错点提醒:
① 事务组名称(springcloud-seata-group)必须和Seata服务端一致,否则微服务无法加入全局事务;
② 数据源代理模式必须设为AT,否则无法生成undo_log快照,回滚失败。
5.3 第三步:编写分布式事务代码(核心,添加注解即可)
Seata AT模式几乎无侵入性,仅需在TM(order-service)的全局事务入口方法上添加@GlobalTransactional注解,即可开启分布式事务,业务代码无需修改。
- 编写order-service业务代码(TM,全局事务入口):
打开order-service的OrderService类,在“创建订单+调用用户服务扣减积分”的方法上添加@GlobalTransactional注解:
package com.example.orderservice.service;
import com.example.orderservice.feign.UserFeignClient;
import com.example.orderservice.mapper.OrderMapper;
import com.example.orderservice.pojo.Order;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class OrderService {
@Resource
private OrderMapper orderMapper;
@Resource
private UserFeignClient userFeignClient;
// 核心:添加@GlobalTransactional注解,开启全局事务
// rollbackFor = Exception.class:所有异常都触发回滚
@GlobalTransactional(rollbackFor = Exception.class)
public String createOrder(Integer userId, String goodsName, Integer num) {
try {
// 1. 本地事务:创建订单(order-service操作订单库)
Order order = new Order();
order.setUserId(userId);
order.setGoodsName(goodsName);
order.setNum(num);
order.setStatus(0); // 0-未支付,1-已支付
orderMapper.insert(order);
System.out.println("订单创建成功!订单ID:" + order.getId());
// 2. 远程调用:调用user-service扣减积分(跨服务操作,user-service操作用户库)
// 模拟扣减10积分(实际业务中积分数量可根据订单金额计算)
String result = userFeignClient.deductPoints(userId, 10);
System.out.println("积分扣减结果:" + result);
return "订单创建成功!订单ID:" + order.getId() + ",积分扣减结果:" + result;
} catch (Exception e) {
// 若出现异常,全局事务回滚(订单创建回滚,积分扣减回滚)
e.printStackTrace();
throw new RuntimeException("订单创建失败,触发分布式事务回滚!");
}
}
}
- 编写user-service业务代码(RM,参与全局事务):
打开user-service的UserService类,编写扣减积分的方法(本地事务,无需添加Seata注解,Seata会自动代理):
package com.example.userservice.service;
import com.example.userservice.mapper.UserMapper;
import com.example.userservice.pojo.User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Service
public class UserService {
@Resource
private UserMapper userMapper;
// 本地事务:扣减积分,Seata会自动将其纳入全局事务
@Transactional(rollbackFor = Exception.class)
public String deductPoints(Integer userId, Integer points) {
// 1. 查询用户信息
User user = userMapper.selectById(userId);
if (user == null) {
throw new RuntimeException("用户不存在!");
}
// 2. 校验积分是否充足
if (user.getPoints() < points) {
throw new RuntimeException("积分不足,扣减失败!");
}
// 3. 扣减积分(本地事务操作)
user.setPoints(user.getPoints() - points);
userMapper.updateById(user);
return "用户ID:" + userId + ",积分扣减成功!当前剩余积分:" + user.getPoints();
}
}
- 编写Feign接口(order-service调用user-service):
在order-service的UserFeignClient中添加扣减积分的接口:
package com.example.orderservice.feign;
import com.example.orderservice.fallback.UserFeignFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "user-service", fallback = UserFeignFallback.class)
public interface UserFeignClient {
// 新增:扣减积分的Feign接口
@GetMapping("/user/deductPoints")
String deductPoints(@RequestParam("userId") Integer userId, @RequestParam("points") Integer points);
// 之前的获取用户信息接口(保留)
@GetMapping("/user/getInfo")
String getUserInfo(@RequestParam("id") Integer id);
}
- 编写user-service接口(供Feign调用):
在user-service的UserController中添加扣减积分的接口:
package com.example.userservice.controller;
import com.example.userservice.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
// 新增:扣减积分接口(供order-service调用)
@GetMapping("/deductPoints")
public String deductPoints(@RequestParam("userId") Integer userId, @RequestParam("points") Integer points) {
return userService.deductPoints(userId, points);
}
// 之前的获取用户信息接口(保留)
@GetMapping("/getInfo")
public String getUserInfo(@RequestParam("id") Integer id) {
return userService.getUserInfo(id);
}
}
- 重新打包微服务镜像,重启容器:
分别进入order-service和user-service根目录,重新打包jar包、构建镜像,然后重启容器:
# 1. 重新打包微服务
mvn clean package -DskipTests
# 2. 重新构建镜像(覆盖原有镜像)
docker build -t springcloud/order-service:1.0 .
docker build -t springcloud/user-service:1.0 .
# 3. 重启容器(一键重启所有服务)
docker compose restart
六、模块四:测试分布式事务效果(核心,验证原子性)
我们分两种场景测试:
① 正常场景(所有服务执行成功);
② 异常场景(某服务执行失败),验证分布式事务的原子性——要么都成功,要么都失败。
6.1 场景一:正常场景(积分充足,所有操作成功)
-
准备数据:在user-service的用户表中,给userId=1的用户设置积分(比如100分);
-
发起请求:用Postman访问order-service的创建订单接口(可通过Gateway转发,地址:http://localhost:8080/gateway/order/create?userId=1&goodsName=手机&num=1);
-
预期结果:
-
接口返回成功:“订单创建成功!订单ID:xxx,积分扣减结果:用户ID:1,积分扣减成功!当前剩余积分:90”;
-
查看数据库:订单库新增一条订单记录,用户库userId=1的用户积分从100变为90;
-
查看undo_log表:order库和user库的undo_log表有记录(执行成功后,Seata会自动删除快照,或标记为已清理)。
6.2 场景二:异常场景(积分不足,触发回滚)
-
准备数据:将userId=1的用户积分修改为5分(小于要扣减的10分);
-
发起请求:再次访问上述创建订单接口;
-
预期结果(核心验证回滚):
-
接口返回失败:“订单创建失败,触发分布式事务回滚!”;
-
查看数据库:订单库无新增订单记录(order-service的本地事务回滚),用户库userId=1的用户积分仍为5分(user-service的本地事务回滚);
-
查看Seata日志:执行
docker logs seata-server,能看到“全局事务回滚”的日志; -
查看undo_log表:order库和user库的undo_log表有快照记录(用于回滚,回滚后可手动清理或配置自动清理)。
补充测试:模拟网络异常——停止user-service容器,发起下单请求,同样会触发全局事务回滚,订单创建失败,确保跨服务异常的原子性。
七、实操总结与易错点复盘
本篇我们完成了Seata AT模式分布式事务的核心实操,成功解决了“跨服务数据一致性”的痛点,实现了“订单创建+积分扣减”的原子性,核心收获如下:
- Seata核心架构:
-
核心角色:TC(事务协调器,Seata服务端)、TM(全局事务发起者,order-service)、RM(事务参与者,order-service、user-service);
-
核心流程:开启全局事务(TM)→ 执行本地事务(RM)→ 全局提交/回滚(TC协调);
- 实操核心步骤:
-
环境准备:创建Seata数据库和undo_log表、配置Nacos全局配置;
-
服务端搭建:Docker+Compose部署Seata TC,注册到Nacos;
-
客户端集成:添加Seata依赖、配置事务组和Nacos地址、在TM入口添加@GlobalTransactional注解;
- 核心价值:解决跨服务数据不一致问题,避免脏数据,筑牢微服务生产环境的数据安全防线,适配下单、支付等核心业务场景。
新手必看易错点(重点避坑,高频问题)
-
版本冲突:Seata服务端和客户端版本必须一致(均为1.5.2),否则微服务无法连接Seata,或回滚失败;
-
事务组名称不一致:微服务客户端的tx-service-group必须和Seata服务端一致,否则无法加入全局事务;
-
未创建undo_log表:参与分布式事务的微服务数据库未创建undo_log表,导致无法生成回滚快照,回滚失败;
-
Seata数据库配置错误:Seata服务端的MySQL地址、用户名、密码错误,导致无法存储全局事务信息,启动失败;
-
未开启数据源代理:微服务客户端未配置seata.datasource.proxy-mode=AT,导致Seata无法代理数据源,无法生成undo_log;
-
注解添加错误:@GlobalTransactional注解添加到了非全局事务入口方法(比如添加到user-service的方法),导致无法开启全局事务;
-
微服务未重启:修改Seata配置或添加依赖后,未重新打包镜像、重启容器,导致配置不生效。
八、下一篇预告
本篇我们解决了微服务跨服务数据一致性的核心痛点,通过Seata AT模式实现了分布式事务,让微服务核心业务(如下单、支付)具备了数据安全性。下一篇将讲解微服务进阶的另一核心优化——高级链路追踪(SkyWalking)实操,替代之前的Zipkin,教大家实现更强大的链路分析、性能监控和慢查询定位,解决Zipkin“仅链路追踪、无性能分析”的不足,进一步提升微服务的可观测性和故障排查效率!
如果这篇实操教程对你有帮助,欢迎点赞、收藏、关注,实操过程中遇到任何问题(比如Seata启动失败、分布式事务回滚无效、微服务无法连接Seata),都可以在评论区留言,我会逐一回复,帮大家解决新手踩坑问题~
补充:需要本篇实操的完整代码(Seata配置文件、微服务业务代码、Feign接口、SQL脚本),评论区扣“Seata分布式事务代码”,我会分享百度网盘链接,方便大家对照学习、直接运行!
更多推荐
所有评论(0)