这是微服务架构中为了保证数据一致性最头疼的一块骨头。
Seata (Simple Extensible Autonomous Transaction Architecture) 是阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
在单体应用中,我们靠数据库本身的事务(ACID)就够了。但在微服务中,订单服务和库存服务连接的是不同的数据库,这就需要 Seata 来充当"大管家",保证"要成功都成功,要失败都回滚"。
1. Seata 核心架构原理 (三剑客)
Seata 的设计中定义了三个核心角色,它们协同工作来完成一个全局事务:
- TC (Transaction Coordinator - 事务协调者):
- 身份 :"大管家"(Seata Server 服务端)。
- 职责:维护全局和分支事务的状态,驱动全局事务提交或回滚。它是独立的中间件,需要单独部署。
- TM (Transaction Manager - 事务管理器):
- 身份 :"发起者"(通常是发起调用的微服务,如订单服务)。
- 职责:定义全局事务的范围。它告诉 TC:"我要开启一个全局事务"、"我要提交"或"我要回滚"。
- RM (Resource Manager - 资源管理器):
- 身份 :"参与者"(各微服务的数据库代理)。
- 职责:管理分支事务处理的资源。它向 TC 注册分支事务,并汇报本地事务的执行状态。

生命周期流程:
- TM 向 TC 申请开启一个全局事务,TC 创建并返回一个唯一的 XID(全局事务 ID)。
- XID 会通过微服务调用链路(Feign/Dubbo)传递给所有下游服务。
- RM (下游服务)在执行 SQL 时,拿到 XID,向 TC 注册分支事务,将其纳入该 XID 的管辖。
- TM 根据所有分支的执行结果,向 TC 发起全局提交或回滚决议。
- TC 调度所有 RM 进行真正的提交或回滚。
2. 什么是二阶提交 (2PC)?
Seata 的模式大多基于 两阶段提交 (Two-Phase Commit) 协议的变种。
-
第一阶段 (Prepare):
-
所有参与者(RM)执行本地事务,但不提交(或者像 Seata AT 那样先提交但保留反悔的证据)。
-
告诉协调者(TC):"我这边准备好了"。
-
第二阶段 (Commit/Rollback):
-
如果所有人都成功,TC 通知大家:"真正的提交"。
-
只要有一个人失败,TC 通知大家:"全部回滚"。
3. Seata 的四种事务模式
Seata 根据业务场景的不同,提供了四种模式。其中 AT 模式 是主打,TCC 是高性能补充。
3.1 AT 模式 (Automatic Transaction) ------ 默认、最常用
这是 Seata 独创的模式,零侵入,开发者像写本地事务一样写代码。
-
原理:
-
一阶段 :业务数据和回滚日志(Undo Log)在同一个本地事务中提交。
-
Seata 会拦截你的 SQL,查询更新前的数据(Before Image)和更新后的数据(After Image),生成 JSON 存入
undo_log表。 -
关键点:本地锁在一阶段就释放了,性能高。
-
二阶段(提交) :异步删除
undo_log记录(极快)。 -
二阶段(回滚) :通过 Undo Log 生成反向 SQL(例如
UPDATE x=1变成UPDATE x=0)并执行,恢复数据。 -
适用场景:基于支持事务的关系型数据库(MySQL, Oracle, PostgreSQL),且对一致性要求不是极其苛刻(允许极短时间的脏读,但 Seata 有全局锁机制防脏写)。
3.2 TCC 模式 (Try-Confirm-Cancel) ------ 高性能
不依赖数据库事务,完全靠业务代码实现。
-
原理:你需要为每个接口写三个方法:
-
Try:资源预留(例如:冻结 100 元,库存 -1 并 冻结库存 +1)。
-
Confirm:真正的业务提交(例如:解冻金额并扣款,解冻库存并扣除)。
-
Cancel:回滚(例如:解冻金额,恢复库存)。
-
优点:不加数据库锁,性能最强。
-
缺点 :代码侵入性极强,一个功能写三个方法,还要考虑幂等性、空回滚、悬挂等问题。
-
适用场景:对性能要求极高,或者操作的不是数据库(比如 Redis、发邮件)。
3.3 XA 模式 ------ 强一致性
利用数据库本身(MySQL 等)支持的 XA 协议。
-
原理:
-
一阶段:执行 SQL 但不提交,持有数据库锁。
-
二阶段:TC 通知数据库进行 Commit 或 Rollback。
-
优点:强一致性(Strong Consistency),标准协议。
-
缺点:性能差。因为从一阶段到二阶段结束,一直持有数据库锁,阻塞其他请求。
3.4 Saga 模式 ------ 长事务
基于状态机引擎。
- 原理:一连串的事务操作,如果中间失败了,就由后向前依次执行补偿操作(Compensation)。
- 适用场景:业务流程极长(比如跨行转账、老旧系统对接),不希望长时间占用数据库连接。
4. Java 代码实战 (AT 模式)
在 Spring Cloud Alibaba 中使用 AT 模式非常简单,核心就是 undo_log 表 和 @GlobalTransactional 注解。
第一步:数据库准备 (必须)
在每一个微服务的数据库中,都必须创建一张 undo_log 表(这是 AT 模式存放"后悔药"的地方)。
SQL 脚本可以在 Seata 官网找到。
第二步:引入依赖
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
第三步:配置 Seata (application.yml)
你需要告诉客户端 Seata Server 在哪。
yaml
seata:
enabled: true
tx-service-group: my_test_tx_group # 事务分组
service:
vgroup-mapping:
my_test_tx_group: default # 映射到 Seata Server 的集群名
registry:
type: nacos # 使用 Nacos 寻找 Seata Server
nacos:
server-addr: 127.0.0.1:8848
第四步:代码使用 (@GlobalTransactional)
只需要在发起全局事务的入口方法(通常是 OrderService)上加上注解即可。
java
@Service
public class OrderService {
@Autowired
private StockFeignClient stockFeignClient;
@Autowired
private AccountFeignClient accountFeignClient;
@Autowired
private OrderMapper orderMapper;
/**
* @GlobalTransactional: 开启全局事务
* name: 事务名称(自定义,用于排查日志)
* rollbackFor: 指定回滚异常
*/
@GlobalTransactional(name = "create-order-tx", rollbackFor = Exception.class)
public void createOrder(Order order) {
// 1. 本地操作:创建订单
orderMapper.insert(order);
// 2. 远程调用:扣减库存 (如果这里报错,Order 会回滚)
stockFeignClient.deduct(order.getProductId(), order.getCount());
// 3. 远程调用:扣减余额 (如果这里报错,Stock 和 Order 都会回滚)
accountFeignClient.debit(order.getUserId(), order.getMoney());
// 4. 模拟异常
if (order.getMoney() < 0) {
throw new RuntimeException("金额非法,触发全局回滚!");
}
}
}
5. 总结与对比表
| 模式 | 侵入性 | 性能 | 一致性 | 机制 | 适用场景 |
|---|---|---|---|---|---|
| AT | 低 | 高 | 最终一致 | 依赖 undo_log,一阶段提交 | 绝大多数业务开发 |
| TCC | 高 | 极高 | 最终一致 | 手写 Try/Confirm/Cancel | 性能极其敏感的核心链路 |
| XA | 低 | 低 | 强一致 | 数据库原生 XA 协议 | 银行金融等绝不能出错的场景 |
| Saga | 中 | 中 | 最终一致 | 状态机 + 补偿机制 | 跨系统长流程业务 |