Seata分布式事务框架
约 1813 字大约 6 分钟
seatadistributed-transaction
2025-04-02
概述
Seata(Simple Extensible Autonomous Transaction Architecture)是阿里巴巴开源的分布式事务解决方案。它提供了 AT、TCC、Saga 和 XA 四种事务模式,通过 TC(Transaction Coordinator)、TM(Transaction Manager)和 RM(Resource Manager)三个核心角色,实现了跨服务的分布式事务一致性。
核心架构
| 角色 | 说明 | 部署方式 |
|---|---|---|
| TC | 事务协调器,维护全局和分支事务的状态,驱动全局事务提交或回滚 | 独立部署的服务端(seata-server) |
| TM | 事务管理器,定义全局事务的边界,负责开启、提交或回滚全局事务 | 嵌入在应用中 |
| RM | 资源管理器,管理分支事务处理的资源,与 TC 通信,注册分支事务、报告分支状态 | 嵌入在应用中 |
四种事务模式
AT 模式(Auto Transaction)
AT 模式是 Seata 最常用的模式,对业务代码无侵入。它通过代理数据源拦截 SQL,自动生成 undo log 实现回滚。
AT 模式执行流程
AT 模式代码示例
// 订单服务 - 全局事务发起方
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private InventoryClient inventoryClient;
@Autowired
private AccountClient accountClient;
@GlobalTransactional(name = "create-order", timeoutMills = 30000,
rollbackFor = Exception.class)
public Order createOrder(OrderRequest request) {
// 1. 创建订单
Order order = new Order();
order.setUserId(request.getUserId());
order.setProductId(request.getProductId());
order.setQuantity(request.getQuantity());
order.setAmount(request.getAmount());
order.setStatus("CREATED");
orderRepository.save(order);
// 2. 扣减库存(远程调用,自动传播XID)
inventoryClient.reduceStock(request.getProductId(), request.getQuantity());
// 3. 扣减账户余额(远程调用)
accountClient.debit(request.getUserId(), request.getAmount());
order.setStatus("COMPLETED");
orderRepository.save(order);
return order;
}
}
// 库存服务 - 分支事务参与方
@Service
public class InventoryService {
@Autowired
private InventoryRepository inventoryRepository;
@Transactional
public void reduceStock(Long productId, int quantity) {
Inventory inventory = inventoryRepository.findByProductId(productId);
if (inventory.getStock() < quantity) {
throw new InsufficientStockException("库存不足");
}
inventory.setStock(inventory.getStock() - quantity);
inventoryRepository.save(inventory);
}
}undo_log 表结构
CREATE TABLE `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 '回滚信息(before/after image)',
`log_status` INT NOT NULL COMMENT '日志状态:0正常,1全局已完成',
`log_created` DATETIME(6) NOT NULL COMMENT '创建时间',
`log_modified` DATETIME(6) NOT NULL COMMENT '修改时间',
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB COMMENT = 'AT事务模式undo日志表';TCC 模式
TCC(Try-Confirm-Cancel)模式需要开发者手动编写三个阶段的业务逻辑,适用于需要精细控制的场景。
// TCC 接口定义
@LocalTCC
public interface InventoryTccAction {
@TwoPhaseBusinessAction(name = "reduceStock",
commitMethod = "confirm", rollbackMethod = "cancel")
boolean tryReduceStock(BusinessActionContext context,
@BusinessActionContextParameter(paramName = "productId")
Long productId,
@BusinessActionContextParameter(paramName = "quantity")
int quantity);
boolean confirm(BusinessActionContext context);
boolean cancel(BusinessActionContext context);
}
// TCC 实现
@Service
public class InventoryTccActionImpl implements InventoryTccAction {
@Autowired
private InventoryRepository inventoryRepository;
@Override
@Transactional
public boolean tryReduceStock(BusinessActionContext context,
Long productId, int quantity) {
// Try阶段:冻结库存
Inventory inventory = inventoryRepository.findByProductId(productId);
if (inventory.getAvailableStock() < quantity) {
throw new InsufficientStockException("可用库存不足");
}
inventory.setAvailableStock(inventory.getAvailableStock() - quantity);
inventory.setFrozenStock(inventory.getFrozenStock() + quantity);
inventoryRepository.save(inventory);
return true;
}
@Override
@Transactional
public boolean confirm(BusinessActionContext context) {
// Confirm阶段:扣减冻结库存
Long productId = context.getActionContext("productId", Long.class);
int quantity = context.getActionContext("quantity", Integer.class);
Inventory inventory = inventoryRepository.findByProductId(productId);
inventory.setFrozenStock(inventory.getFrozenStock() - quantity);
inventoryRepository.save(inventory);
return true;
}
@Override
@Transactional
public boolean cancel(BusinessActionContext context) {
// Cancel阶段:解冻库存
Long productId = context.getActionContext("productId", Long.class);
int quantity = context.getActionContext("quantity", Integer.class);
Inventory inventory = inventoryRepository.findByProductId(productId);
inventory.setAvailableStock(inventory.getAvailableStock() + quantity);
inventory.setFrozenStock(inventory.getFrozenStock() - quantity);
inventoryRepository.save(inventory);
return true;
}
}Saga 模式
Saga 模式适用于长事务场景,每个参与者提供正向操作和补偿操作,通过状态机编排事务流程。
XA 模式
XA 模式基于数据库的 XA 协议实现强一致性,但性能开销较大。
@GlobalTransactional
public void xaTransfer(String from, String to, BigDecimal amount) {
// XA模式下,本地事务不会提交,等待TC协调
accountRepository.debit(from, amount);
accountRepository.credit(to, amount);
}四种模式对比
| 特性 | AT | TCC | Saga | XA |
|---|---|---|---|---|
| 侵入性 | 低(无侵入) | 高(需写三个方法) | 中 | 低 |
| 一致性 | 最终一致性 | 最终一致性 | 最终一致性 | 强一致性 |
| 性能 | 高 | 高 | 高 | 低 |
| 隔离性 | 全局锁 | 业务保证 | 无隔离 | 数据库隔离 |
| 适用场景 | 大部分OLTP | 资金类业务 | 长事务 | 强一致性要求 |
全局锁机制
AT 模式通过全局锁保证写隔离:
配置示例
# application.yml
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: my_tx_group
config:
type: nacos
nacos:
server-addr: nacos:8848
namespace: seata
group: SEATA_GROUP
data-id: seataServer.properties
registry:
type: nacos
nacos:
server-addr: nacos:8848
namespace: seata
group: SEATA_GROUP
application: seata-server
service:
vgroup-mapping:
my_tx_group: default总结
Seata 提供了四种分布式事务模式,覆盖不同业务场景:AT 模式无侵入适合大部分场景,TCC 模式适合资金类业务,Saga 模式适合长事务流程,XA 模式保证强一致性。TC/TM/RM 三角色架构清晰,配合 Nacos 注册配置中心可实现高可用部署。选择合适的事务模式需要在一致性、性能和开发成本之间权衡。
贡献者
更新日志
2026/3/14 13:09
查看所有更新日志
9f6c2-feat: organize wiki content and refresh site setup于