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 专用的分支事务上下文,功能和使用场景各有侧重。
相关推荐
嘉友30 分钟前
Redis zset数据结构以及时间复杂度总结(源码)
数据结构·数据库·redis·后端
苏三说技术2 小时前
Excel百万数据如何快速导入?
后端
昵称为空C2 小时前
SpringBoot编码技巧-ScheduledExecutorService轮询
java·spring boot·后端
huangyingying20252 小时前
03-分支结构
后端
00后程序员2 小时前
【Flutter -- 基础组件】Flutter 导航栏
后端
bobz9652 小时前
ovs internal port 对比 veth-pair 性能
后端
Auroral1562 小时前
基于RabbitMQ的异步通知系统设计与实现
前端·后端
易元2 小时前
设计模式-代理模式
java·后端
嘻嘻哈哈开森2 小时前
Java开发工程师转AI工程师
人工智能·后端
LTPP3 小时前
自动化 Rust 开发的革命性工具:lombok-macros
前端·后端·github