Spring Cloud集成seata分布式事务-TCC模式

本文将介绍基于springcloud+feign使用阿里巴巴分布式事务框架seata的TCC模式(1.0.0版本),在前一篇文章已经介绍过,AT模式基本上能满足我们使用分布式事务80%的需求。但涉及非关系型数据库与中间件(如redis等)的操作、跨公司服务的调用跨语言的应用调用需要结合TCC模式。关于seata的介绍可以点击这里进入seata官网

 一、TCC模式的概念

一个分布式的全局事务,整体是两阶段提交(Try-[Comfirm/Cancel])的模型。在SEATA中,AT模式与TCC模式事实上都是基于两阶段提交实现。他们的区别在于:

AT 模式基于 支持本地 ACID 事务 的 关系型数据库

  • 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
  • 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
  • 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。

相应的,TCC 模式,不依赖于底层数据资源的事务支持:

  • 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
  • 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
  • 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。

所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。

简单点概括,SEATA的TCC模式就是手工的AT模式,它允许你自定义两阶段的处理逻辑而不依赖AT模式的undo_log。

二、前提准备

三、TM与TCC-RM的搭建(源码点此)

本章着重讲基于SpringCloud+Feign的TCC的实现,项目的搭建直接看源码

3.1 seata服务端的搭建

3.2 TM的搭建

3.3 TCC-RM的搭建

3.3.1 定义TCC接口

由于我们使用的是SpringCloud+Feign,Feign的调用基于http,因此此处我们使用LocalTCC便可。值得注意的是,@LocalTCC一定需要注解在接口上,此接口可以是寻常的业务接口,只要实现了TCC的两阶段提交对应方法便可。

  • @LocalTCC 适用于SpringCloud+Feign模式下的TCC
  • @TwoPhaseBusinessAction 注解try方法,其中name为当前tcc方法的bean名称,写方法名便可(记得全局唯一),commitMethod指向提交方法,rollbackMethod指向事务回滚方法。指定好三个方法之后,seata会根据事务的成功或失败,通过动态代理去帮我们自动调用提交或者回滚。
  • @BusinessActionContextParameter 注解可以将参数传递到二阶段(commitMethod/rollbackMethod)的方法。
  • BusinessActionContext 便是指TCC事务上下文
/**
 * 这里定义tcc的接口
 * 一定要定义在接口上
 * 我们使用springCloud的远程调用
 * 那么这里使用LocalTCC便可
 *
 * @author tanzj
 */
@LocalTCC
public interface TccService {

    /**
     * 定义两阶段提交
     * name = 该tcc的bean名称,全局唯一
     * commitMethod = commit 为二阶段确认方法
     * rollbackMethod = rollback 为二阶段取消方法
     * BusinessActionContextParameter注解 可传递参数到二阶段方法
     *
     * @param params  -入参
     * @return String
     */
    @TwoPhaseBusinessAction(name = "insert", commitMethod = "commitTcc", rollbackMethod = "cancel")
    String insert(
            @BusinessActionContextParameter(paramName = "params") Map<String, String> params
    );

    /**
     * 确认方法、可以另命名,但要保证与commitMethod一致
     * context可以传递try方法的参数
     *
     * @param context 上下文
     * @return boolean
     */
    boolean commitTcc(BusinessActionContext context);

    /**
     * 二阶段取消方法
     *
     * @param context 上下文
     * @return boolean
     */
    boolean cancel(BusinessActionContext context);
}

3.3.2 TCC接口的业务实现

为了保证代码的简洁,此处将Controller与Service结合讲解,实际项目则不然。

  • 在try方法中使用@Transational可以直接通过spring事务回滚关系型数据库中的操作,而非关系型数据库等中间件的回滚操作可以交给rollbackMethod方法处理。
  • 使用context.getActionContext("params")便可以得到一阶段try中定义的参数,在二阶段对此参数进行业务回滚操作。
  • 注意,此处亦不可以捕获异常(同理切面处理异常),否则TCC将识别该操作为成功,二阶段直接执行commitMethod。
  • 二阶段commitMethod可以空确认。
@Slf4j
@RestController
public class TccServiceImpl implements  TccService {

    @Autowired
    TccDAO tccDAO;

    /**
     * tcc服务t(try)方法
     * 实际业务方法
     *
     * @param params - name
     * @return String
     */
    @Override
    @PostMapping("/tcc-insert")
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public String insert(@RequestBody Map<String, String> params) {
        log.info("------------------> xid = " + RootContext.getXID());
        //实际的操作,或操作MQ、redis等
        tccDAO.insert(params);
        //throw new RuntimeException("服务tcc测试回滚");
        return "success";
    }

    /**
     * tcc服务 confirm方法
     * 可以空确认
     *
     * @param context 上下文
     * @return boolean
     */
    @Override
    public boolean commitTcc(BusinessActionContext context) {
        log.info("xid = " + context.getXid() + "提交成功");
        return true;
    }

    /**
     * tcc 服务 cancel方法
     *
     * @param context 上下文
     * @return boolean
     */
    @Override
    public boolean cancel(BusinessActionContext context) {
        //todo 这里写中间件、非关系型数据库的回滚操作
        System.out.println("please manually rollback this data:" + context.getActionContext("params"));
        return true;
    }
}

3.3.3 seata相关yml配置(单机版)

seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: seataGroup-${seata.application-id}
  service:
    vgroup-mapping: default
    grouplist: 127.0.0.1:8091
  config:
    type: file
    file:
      name: file.conf
  registry:
    type: nacos
    file:
      name: file.conf

至此完成seata-tcc模式的配置工作。

猜你喜欢

转载自blog.csdn.net/bbcckkl/article/details/104524095