前言
这篇文章我主要演示在Spring中如何使用seata框架的TCC事务模式,并不会区过深研究TCC的模型,那么还是首先来简单介绍一下什么是TCC
简介
Seata TCC 模式
一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的,分支事务要满足 两阶段提交 的模型要求,即需要每个分支事务都具备自己的:
- 一阶段 prepare 行为
- 二阶段 commit 或 rollback 行为
有点类似于Java中的try-catch
操作,来看下面更好的理解它
- 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
- 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
- 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
这样看起来就更明白了,所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。
示例
假设我们有一个服务A和服务B,服务A为入口,在服务A的代码逻辑中需要调用服务B的接口,使用TCC的模式来保证他们的事务安全问题。
服务A的Service接口
@LocalTCC
public interface CityTCC extends IService<City> {
@TwoPhaseBusinessAction(name = "prepare", commitMethod = "commit", rollbackMethod = "rollback")
void prepare(@BusinessActionContextParameter(paramName = "name") String name,
@BusinessActionContextParameter(paramName = "address") String address);
boolean commit(BusinessActionContext context);
boolean rollback(BusinessActionContext context);
}
- @LocalTCC:作用于服务接口上,表示实现该接口的实现类被 seata 来管理,seata 根据事务的状态,自动调用我们定义的方法,如果没问题则调用 Commit 方法,否则调用 Rollback 方法。
- @TwoPhaseBusinessAction:该注解用在接口的 Try 方法上,name 为 tcc 方法的 bean 名称,需要全局唯一,一般写方法名即可
- @BusinessActionContextParameter:该注解用来修饰 Try 方法的入参,被修饰的入参可以在 Commit 方法和 Rollback 方法中通过 BusinessActionContext 获取。
服务A接口实现
@Service
@Slf4j
public class CityTCCImpl extends ServiceImpl<CityMapper, City> implements CityTCC {
@Resource
private CityMapper cityMapper;
@Resource
private FeignServiceB serviceB;
@Override
@Transactional
public void prepare(String name, String address) {
log.info("执行try操作");
//一般为锁定资源阶段,判断资源是否存在,对资源进行修改操作等等...
//如果当前try操作没有发生异常,则会执行commit方法体内容
}
@Override
@Transactional
public boolean commit(BusinessActionContext context) {
log.info("执行commit操作");
City city = new City();
city.setName(context.getActionContext("name"));
city.setAddress(context.getActionContext("address"));
try{
cityMapper.insert(city);
//调用B服务的方法
serviceB.addCityArea();
return true;
}catch(Exception e){
return false;
}
}
@Override
@Transactional
public boolean rollback(BusinessActionContext context) {
//手动执行回滚业务逻辑......比如把已修改的状态在修改回来等,根据你们的需求进行自定义操作
log.info("执行rollback操作");
return true;
}
}
服务A的接口
@RestController
@RequestMapping("/city")
public class CityController {
@Resource
private CityService cityService;
@RequestMapping("/addCity")
@GlobalTransactional//在入口函数上添加全局事务管理
public void tccAddCity(@RequestParam("name")String name,
@RequestParam("address")String address) {
cityService.prepare(name, address);
}
}
流程讲解
当请求调用服务A的/city/addCity
请求时,首先会走到prepare
方法中进行操作,如果该方法没有发生异常,则自动走到commit方法中执行,判断最后返回的布尔值是否为true,如果为false则不会进行添加入库操作。
总结
这只是一个简单的TCC模式使用案例,仅供参考如果哪里有问题可以在评论区讨论一下。本篇文章就到这里了,再见啦