第三章:AT 模式¶
AT 模式原理¶
工作流程¶
AT 模式工作流程:
一阶段:
1. 解析 SQL
2. 记录 undo_log(修改前数据)
3. 执行 SQL
4. 记录 undo_log(修改后数据)
5. 获取全局锁
6. 提交本地事务
二阶段(提交):
1. 异步删除 undo_log
二阶段(回滚):
1. 根据 undo_log 回滚数据
2. 释放全局锁
示例¶
-- 原始数据
UPDATE account SET balance = balance - 100 WHERE id = 1;
-- undo_log 记录
{
"beforeImage": {
"rows": [{"id": 1, "balance": 1000}]
},
"afterImage": {
"rows": [{"id": 1, "balance": 900}]
}
}
-- 回滚时执行
UPDATE account SET balance = 1000 WHERE id = 1;
快速开始¶
服务端部署¶
# 下载 Seata Server
wget https://github.com/seata/seata/releases/download/v1.7.0/seata-server-1.7.0.tar.gz
tar -xzf seata-server-1.7.0.tar.gz
cd seata
# 启动
sh bin/seata-server.sh
客户端配置¶
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.7.0</version>
</dependency>
# application.yml
seata:
enabled: true
application-id: order-service
tx-service-group: my_tx_group
service:
vgroup-mapping:
my_tx_group: default
registry:
type: nacos
nacos:
server-addr: localhost:8848
namespace: public
group: SEATA_GROUP
创建 undo_log 表¶
-- 每个数据库都需要创建
CREATE TABLE `undo_log` (
`id` bigint NOT NULL AUTO_INCREMENT,
`branch_id` bigint NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int 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;
使用示例¶
开启事务¶
import io.seata.spring.annotation.GlobalTransactional;
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private AccountService accountService;
@Autowired
private StorageService storageService;
@GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
public void createOrder(Order order) {
// 创建订单
orderMapper.insert(order);
// 扣减余额
accountService.decreaseBalance(order.getUserId(), order.getAmount());
// 扣减库存
storageService.decreaseStock(order.getProductId(), order.getCount());
}
}
分支事务¶
@Service
public class AccountService {
@Autowired
private AccountMapper accountMapper;
public void decreaseBalance(Long userId, BigDecimal amount) {
Account account = accountMapper.selectByUserId(userId);
if (account.getBalance().compareTo(amount) < 0) {
throw new RuntimeException("余额不足");
}
accountMapper.decreaseBalance(userId, amount);
}
}
配置详解¶
注册中心配置¶
seata:
registry:
type: nacos
nacos:
server-addr: localhost:8848
namespace: public
group: SEATA_GROUP
application: seata-server
配置中心配置¶
数据源代理¶
import io.seata.rm.datasource.DataSourceProxy;
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return new DruidDataSource();
}
@Bean
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
}
注意事项¶
1. SQL 支持¶
2. 主键要求¶
3. 字段类型¶
小结¶
AT 模式要点:
- 原理:一阶段记录 undo_log,二阶段提交/回滚
- 快速开始:服务端部署、客户端配置
- 使用示例:@GlobalTransactional
- 配置详解:注册中心、配置中心、数据源代理
- 注意事项:SQL 支持、主键要求、字段类型
下一章我们将学习 TCC 模式。