Seata AT模式详解
AT模式原理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20执行流程:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 业务SQL │ │ 解析SQL │ │ 生成回滚SQL │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 记录前镜像 │ ──► │ 执行业务SQL │ ──► │ 记录后镜像 │
└─────────────┘ └─────────────┘ └─────────────┘
两阶段提交:
Phase 1: Try
- 业务SQL执行
- 解析SQL
- 记录前后镜像
- 生成回滚日志
Phase 2: Commit/Rollback
- Commit: 删除回滚日志
- Rollback: 根据镜像生成反向SQL核心组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// 1. 数据源代理
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
// 配置数据源
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
// 使用Seata代理数据源
return new DataSourceProxy(dataSource);
}
// 2. 全局事务注解
public void businessMethod() {
// 订单服务
orderService.create(order);
// 库存服务
stockService.deduct(stock);
// 账户服务
accountService.debit(money);
}实际应用场景
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23场景一:电商下单
┌─────────────┐
│ 下单服务 │
└──────┬──────┘
│
▼
┌──────┴──────┐ ┌─────────────┐ ┌─────────────┐
│ 订单服务 │ ──► │ 库存服务 │ ──► │ 账户服务 │
└─────────────┘ └─────────────┘ └─────────────┘
订单表 库存表 账户表
- 创建订单 - 扣减库存 - 扣减余额
场景二:积分兑换
┌─────────────┐
│ 兑换服务 │
└──────┬──────┘
│
▼
┌──────┴──────┐ ┌─────────────┐
│ 积分服务 │ ──► │ 商品服务 │
└─────────────┘ └─────────────┘
积分表 库存表
- 扣减积分 - 扣减库存实现示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27// 订单服务
public void createOrder(OrderDTO orderDTO) {
// 1. 创建订单
Order order = new Order();
order.setUserId(orderDTO.getUserId());
order.setAmount(orderDTO.getAmount());
orderMapper.insert(order);
// 2. 调用库存服务
Result stockResult = stockService.deduct(
orderDTO.getProductId(),
orderDTO.getQuantity()
);
if (!stockResult.isSuccess()) {
throw new BusinessException("库存不足");
}
// 3. 调用账户服务
Result accountResult = accountService.debit(
orderDTO.getUserId(),
orderDTO.getAmount()
);
if (!accountResult.isSuccess()) {
throw new BusinessException("余额不足");
}
}优缺点分析
1
2
3
4
5
6
7
8
9
10
11优点:
1. 对业务无侵入
2. 无需手动编写回滚逻辑
3. 性能损耗小
4. 兼容已有数据库
缺点:
1. 依赖数据库事务
2. 需要代理数据源
3. 无法处理复杂业务
4. 表需要主键和索引使用建议
1
2
3
4
5
6
7
8
9
10
11适用场景:
1. 简单的数据库操作
2. 常规的CRUD业务
3. 对性能要求不是特别高
4. 数据库支持事务
不适用场景:
1. 复杂业务逻辑
2. 高并发场景
3. 涉及非事务性资源
4. 跨数据库类型性能优化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SeataConfig {
public GlobalTransactionScanner globalTransactionScanner() {
return new GlobalTransactionScanner(
"order-service", // 应用名
"my_test_tx_group" // 事务分组
);
}
// 配置事务分组
public ConfigurationCache configurationCache() {
ConfigurationCache cache = new ConfigurationCache();
cache.putConfig(
"service.vgroupMapping.my_test_tx_group",
"default"
);
return cache;
}
}