Seata 的 AT (Automatic Transaction) 模式是 Seata 中实现分布式事务的主要方式之一。AT 模式通过自动化的机制实现了两阶段提交(2PC),使得开发人员无需关心底层的事务细节。下面我们将详细解析 Seata 1.4.2 版本中 AT 模式的执行流程。
AT 模式的执行流程
1. 事务开始
当应用程序启动一个分布式事务时,Seata 的客户端(通常是 Spring Cloud 应用)会向 Seata Server 发送请求,开始一个新的全局事务。
- 客户端:在客户端应用中,通过注解
@GlobalTransactional
或者编程式 API 来标记需要参与全局事务的方法。 - Seata Server:Seata Server 收到请求后,生成一个全局事务 ID (
XID
),并记录到全局事务表global_table
中。
2. 分支注册
- 客户端:客户端应用在执行本地事务的过程中,每遇到一次数据库操作,都会生成一个分支事务 ID (
Branch ID
),并将该分支事务注册到 Seata Server。 - Seata Server:Seata Server 收到分支注册请求后,将分支事务的信息记录到分支事务表
branch_table
中。
3. 执行本地操作
- 客户端:客户端继续执行本地事务中的业务逻辑,同时 Seata 会在每个 SQL 语句执行前后记录下 Undo Log(回滚日志),以便在事务回滚时能够还原数据。
- Undo Log:Undo Log 包括两部分:
Before Image
和After Image
,分别记录了数据修改前后的状态。
4. 事务提交或回滚
- 客户端:业务逻辑执行完毕后,客户端决定提交或回滚全局事务。
- Seata Server:
- 如果决定提交全局事务,Seata Server 会向所有注册的分支事务发送提交命令。
- 如果决定回滚全局事务,Seata Server 会向所有注册的分支事务发送回滚命令。
5. 分支提交或回滚
- 客户端:
- 提交:如果接收到提交命令,客户端将提交本地事务,并清理 Undo Log。
- 回滚:如果接收到回滚命令,客户端将使用 Undo Log 来回滚本地事务。
6. 事务结束
- Seata Server:Seata Server 根据分支事务的结果更新全局事务的状态,并最终清理相关记录。
执行流程总结
- 事务开始:客户端通过注解或 API 标记开始全局事务,Seata Server 生成全局事务 ID。
- 分支注册:客户端在执行本地事务过程中,为每个数据库操作注册分支事务。
- 执行本地操作:客户端执行业务逻辑,Seata 记录 Undo Log。
- 事务提交或回滚:客户端决定提交或回滚全局事务。
- 分支提交或回滚:Seata Server 向分支事务发送提交或回滚命令。
- 事务结束:Seata Server 更新全局事务状态,并清理记录。
关键组件和表
- global_table:存储全局事务的状态和相关信息。
- branch_table:存储分支事务的状态和相关信息。
- undo_log:记录分支事务的 Undo Log,用于回滚操作。
- lock_table:存储事务执行过程中的锁定信息,确保事务的一致性。
示例代码
下面是一个简单的示例,展示了如何在 Spring Boot 应用中使用 Seata 的 AT 模式:
@Service
public class AccountService {
@Autowired
private AccountRepository accountRepository;
@GlobalTransactional
public void transfer(String fromName, String toName, int amount) {
// 查询转账前账户余额
Account fromAccount = accountRepository.findByName(fromName);
Account toAccount = accountRepository.findByName(toName);
// 扣减转出账户余额
fromAccount.setBalance(fromAccount.getBalance() - amount);
accountRepository.save(fromAccount);
// 增加转入账户余额
toAccount.setBalance(toAccount.getBalance() + amount);
accountRepository.save(toAccount);
}
}
@RestController
public class AccountController {
@Autowired
private AccountService accountService;
@PostMapping("/transfer")
public String transfer(@RequestParam("from") String fromName, @RequestParam("to") String toName, @RequestParam("amount") int amount) {
accountService.transfer(fromName, toName, amount);
return "Transfer successful";
}
}
在这个例子中,@GlobalTransactional
注解用于标记 transfer
方法参与全局事务。当该方法被调用时,Seata 会自动处理事务的开始、分支注册、本地操作、提交或回滚等流程。
希望这个解析对您有所帮助!如果您有任何疑问或需要进一步的解释,请随时告诉我。