Seata TCC 模式:RootContext与TCC专属的BusinessActionContext与TCC注解详解


深入剖析 Seata TCC 模式:注解与上下文详解

Seata 是一款由阿里巴巴开源的分布式事务解决方案,支持 AT、TCC、Saga 和 XA 等多种事务模式。TCC(Try-Confirm-Cancel)模式因其灵活性和高性能,特别适合需要手动控制事务逻辑的场景。本文将详细介绍 Seata TCC 模式中的注解及其上下文(BusinessActionContext),并探讨全局事务中常见的 RootContext 与 TCC 模式中使用的 BusinessActionContext 的联系与差异。我们还会深入分析上下文的来源、调用方式以及值的获取过程。

一、Seata TCC 模式的核心注解

在 TCC 模式中,开发者通过注解定义事务的三个阶段(Try、Confirm、Cancel)。这些注解是 TCC 模式的基础,以下是它们的具体作用和用法。

1. @LocalTCC

  • 作用:标记一个接口为 TCC 接口,表示该接口包含 TCC 事务逻辑。

  • 使用位置:必须定义在接口上,而非实现类。

  • 意义 :Seata 会扫描并解析该接口为 TCC 资源(TCCResource),以便在全局事务中管理。

  • 示例

    java 复制代码
    @LocalTCC
    public interface TccService {
        // TCC 方法定义
    }

2. @TwoPhaseBusinessAction

  • 作用:定义 Try 阶段的方法,并指定 Confirm 和 Cancel 阶段的对应方法。

  • 属性

    • name:TCC 方法的全局唯一标识,用于注册 TCC 资源。
    • commitMethod:指定二阶段确认方法的名称。
    • rollbackMethod:指定二阶段回滚方法的名称。
  • 使用位置:Try 阶段的方法。

  • 示例

    java 复制代码
    @TwoPhaseBusinessAction(name = "insertTcc", commitMethod = "commitTcc", rollbackMethod = "cancelTcc")
    String insert(@BusinessActionContextParameter(paramName = "params") Map<String, String> params);

3. @BusinessActionContextParameter

  • 作用 :将 Try 阶段的参数传递到上下文(BusinessActionContext),以便在 Confirm 或 Cancel 阶段使用。

  • 属性

    • paramName:参数在上下文中的键名。
  • 使用位置:Try 方法的参数。

  • 示例

    java 复制代码
    String insert(@BusinessActionContextParameter(paramName = "params") Map<String, String> params);

    在 Confirm 或 Cancel 阶段,可通过 context.getActionContext("params") 获取该参数。

4. Confirm 和 Cancel 方法

  • 作用 :分别定义二阶段的提交和回滚逻辑,无需额外注解,但需与 @TwoPhaseBusinessAction 中的 commitMethodrollbackMethod 名称一致。

  • 参数 :通常接收 BusinessActionContext 对象,用于获取上下文信息。

  • 示例

    java 复制代码
    boolean commitTcc(BusinessActionContext context);
    boolean cancelTcc(BusinessActionContext context);

二、上下文(BusinessActionContext)的全面解析

在 TCC 模式中,BusinessActionContext 是连接 Try、Confirm 和 Cancel 三个阶段的关键。它存储和传递事务相关信息,以下是其来源、调用方式及内容的详细说明。

1. 上下文的来源

  • 创建时机 :当 Try 方法被调用时,Seata 的 TccActionInterceptor 拦截器为该分支事务创建 BusinessActionContext 实例。
  • 填充过程
    1. 全局事务 ID(XID) :由事务发起方通过 @GlobalTransactional 注解开启全局事务时生成,通过 RootContext.getXID() 传播。
    2. 分支事务 ID(Branch ID) :Try 方法执行时,Seata 的资源管理器(RM)向事务协调者(TC)注册分支事务,TC 返回唯一的 branchId
    3. 用户参数 :通过 @BusinessActionContextParameter 注解指定的参数值被存入上下文。
    4. 其他元数据 :如 resourceId(TCC 方法的 name)、应用信息等,由 Seata 自动填充。
  • 传播机制:上下文通过拦截器和 RPC 调用在分布式系统中传递,确保 Confirm 和 Cancel 阶段能获取 Try 阶段的信息。

2. 如何调用上下文

  • 获取方式 :在 Confirm 和 Cancel 方法中,BusinessActionContext 作为参数直接传入。

  • 常用方法

    • getXid():获取全局事务 ID。
    • getBranchId():获取当前分支事务 ID。
    • getActionContext(String key):获取 Try 阶段传递的参数值。
    • getActionName():获取 TCC 方法的名称(name 属性)。
  • 示例

    java 复制代码
    public boolean commitTcc(BusinessActionContext context) {
        String xid = context.getXid();
        long branchId = context.getBranchId();
        Map<String, String> params = (Map<String, String>) context.getActionContext("params");
        System.out.println("XID: " + xid + ", Branch ID: " + branchId + ", Params: " + params);
        return true;
    }

3. 上下文中的值如何获取

  • XID :由事务管理器(TM)在全局事务开启时向 TC 注册生成,存储在 RootContext 中,通过线程上下文传播。
  • Branch ID :由 RM 在 Try 阶段向 TC 注册分支事务时,TC 返回并填充到 BusinessActionContext
  • 用户参数 :通过 @BusinessActionContextParameter 在 Try 阶段注入,Seata 序列化后存入上下文。
  • 其他信息 :如 resourceId@TwoPhaseBusinessActionname 获取,应用信息从配置或运行时环境提取。

三、RootContext 与 BusinessActionContext 的差异

Seata 的全局事务管理中,RootContextBusinessActionContext 是两个关键上下文类。以下是它们的对比和联系:

1. RootContext

  • 作用:全局事务的线程上下文,存储全局事务的基本信息,适用于所有事务模式(AT、TCC、Saga、XA)。
  • 主要方法
    • getXID():获取全局事务 ID。
    • getBranchId():获取当前线程的分支事务 ID(若存在)。
  • 特点
    • 线程级别,通过 ThreadLocal 实现。
    • 不包含 TCC 特有的用户参数或资源信息。
    • 在全局事务范围内传播,任何地方都可以通过 RootContext.getXID() 获取 XID。
  • 使用场景:通常在事务发起方或需要检查事务状态时使用。

2. BusinessActionContext

  • 作用:TCC 模式专用的上下文对象,连接 Try、Confirm 和 Cancel 阶段。
  • 主要方法 :如上所述(getXid()getBranchId()getActionContext() 等)。
  • 特点
    • 仅在 TCC 模式中使用,不适用于 AT 或其他模式。
    • 包含 TCC 特有的信息,如用户通过 @BusinessActionContextParameter 传递的参数。
    • 通过方法参数传递,仅在 Confirm 和 Cancel 阶段可用。
  • 使用场景:TCC 的二阶段逻辑中,用于获取 Try 阶段的数据。

3. 差异与联系

  • 范围RootContext 是全局的,贯穿整个事务生命周期;BusinessActionContext 是分支事务级别的,仅在 TCC 分支中使用。
  • 内容RootContext 只存储 XID 和 Branch ID 等基本信息;BusinessActionContext 额外包含 TCC 的用户参数和资源信息。
  • 独特性BusinessActionContext 是 TCC 模式独有的,AT 模式依赖 undo_log 而无需显式上下文。
  • 联系 :两者都依赖 XID 和 Branch ID 的生成逻辑,BusinessActionContext 的 XID 来源于 RootContext

四、上下文的完整示例

以下是一个 TCC 接口的完整实现,展示上下文的使用:

java 复制代码
@LocalTCC
public interface TccService {
    @TwoPhaseBusinessAction(name = "insertTcc", commitMethod = "commitTcc", rollbackMethod = "cancelTcc")
    String insert(@BusinessActionContextParameter(paramName = "params") Map<String, String> params);

    boolean commitTcc(BusinessActionContext context);

    boolean cancelTcc(BusinessActionContext context);
}

@Service
public class TccServiceImpl implements TccService {
    @Override
    public String insert(Map<String, String> params) {
        System.out.println("Try phase, params: " + params);
        return "success";
    }

    @Override
    public boolean commitTcc(BusinessActionContext context) {
        String xid = context.getXid();
        long branchId = context.getBranchId();
        Map<String, String> params = (Map<String, String>) context.getActionContext("params");
        System.out.println("Confirm phase, XID: " + xid + ", Branch ID: " + branchId + ", Params: " + params);
        return true;
    }

    @Override
    public boolean cancelTcc(BusinessActionContext context) {
        String xid = context.getXid();
        long branchId = context.getBranchId();
        Map<String, String> params = (Map<String, String>) context.getActionContext("params");
        System.out.println("Cancel phase, XID: " + xid + ", Branch ID: " + branchId + ", Params: " + params);
        return true;
    }
}

五、总结

  • TCC 注解@LocalTCC 定义 TCC 接口,@TwoPhaseBusinessAction 指定三阶段方法,@BusinessActionContextParameter 传递参数到上下文。
  • 上下文来源BusinessActionContext 由 Seata 在 Try 阶段创建,通过拦截器和 TC 注册填充数据。
  • 调用与值获取 :通过 BusinessActionContext 的方法获取 XID、Branch ID 和用户参数。
  • RootContext vs. BusinessActionContext:前者是全局事务的线程上下文,后者是 TCC 专用的分支事务上下文,功能和使用场景各有侧重。
相关推荐
invicinble1 小时前
对于springboot
java·spring boot·后端
码界奇点1 小时前
基于Spring Boot与Vue的校园后台管理系统设计与实现
vue.js·spring boot·后端·毕业设计·源代码管理
爱编程的小庄1 小时前
Rust 发行版本及工具介绍
开发语言·后端·rust
Apifox.3 小时前
测试用例越堆越多?用 Apifox 测试套件让自动化回归更易维护
运维·前端·后端·测试工具·单元测试·自动化·测试用例
sunnyday04263 小时前
Nginx与Spring Cloud Gateway QPS统计全攻略
java·spring boot·后端·nginx
康王有点困3 小时前
Link入门
后端·flink
海南java第二人3 小时前
Spring Boot全局异常处理终极指南:打造优雅的API错误响应体系
java·spring boot·后端
小楼v4 小时前
消息队列的核心概念与应用(RabbitMQ快速入门)
java·后端·消息队列·rabbitmq·死信队列·交换机·安装步骤
小北方城市网4 小时前
接口性能优化实战:从秒级到毫秒级
java·spring boot·redis·后端·python·性能优化
鸡蛋豆腐仙子4 小时前
Spring的AOP失效场景
java·后端·spring