11.7. 练习中的事务使用


11.7.1. 事务使用情况概述

当您需要在应用中使用事务时,以下步骤非常有用。

11.7.2. 控制事务

简介

本流程列表概述了控制应用中使用 Jakarta Transactions API 的不同方法。

11.7.2.1. 开始交易

此流程演示了如何开始新交易。无论您运行配置了 Jakarta Transactions 或 JTS 的事务管理器™,API 都相同。

  1. 获取 UserTransaction 实例.

    如果 Jakarta Enterprise Beans 使用 @TransactionManagement(TransactionManagement)注释(TransactionManagementType.BEAN) 注释,则可以使用 Java 命名和目录接口、注入或 Jakarta Enterprise Beans 上下文获取实例。

    • 使用 Java 命名和目录界面获取实例。

      new InitialContext().lookup("java:comp/UserTransaction")
      Copy to Clipboard Toggle word wrap
    • 使用注入获取实例。

      @Resource UserTransaction userTransaction;
      Copy to Clipboard Toggle word wrap
    • 使用 Jakarta Enterprise Beans 上下文获取实例。

      • 在无状态/状态 Bean 中:

        @Resource SessionContext ctx;
        ctx.getUserTransaction();
        Copy to Clipboard Toggle word wrap
      • 在消息驱动型 Bean 中:

        @Resource MessageDrivenContext ctx;
        ctx.getUserTransaction()
        Copy to Clipboard Toggle word wrap
  2. 连接到数据源后,请致电 UserTransaction.begin( )。

    try {
        System.out.println("\nCreating connection to database: "+url);
        stmt = conn.createStatement();  // non-tx statement
        try {
            System.out.println("Starting top-level transaction.");
            userTransaction.begin();
            stmtx = conn.createStatement(); // will be a tx-statement
            ...
        }
    }
    Copy to Clipboard Toggle word wrap

结果

事务开始。在提交或回滚事务之前,数据源的所有用途都是事务性。

有关完整示例,请参阅 Jakarta Transactions 交易示例

注意

Jakarta Enterprise Beans(用于 CMT 或 BMT)的好处之一是,容器管理事务处理的所有内部,也就是说,您可以免于处理作为 JBoss EAP 容器中 XA 事务处理一部分的事务处理或事务分配。

11.7.2.1.1. 嵌套事务

嵌套交易允许应用创建嵌入在现有事务中的事务。在此模型中,多个子事务可以递归地嵌入到事务中。子事务可以提交或回滚,无需提交或回滚父事务。但是,提交操作的结果取决于所有交易先锋的承诺。

有关具体实施的信息,请参阅 Narayana 项目文档

嵌套事务仅在与 JTS 规范一起使用时才可用。嵌套事务不是 JBoss EAP 应用服务器的支持功能。此外,许多数据库供应商不支持嵌套交易,因此请在向应用添加嵌套事务前咨询您的数据库供应商。

11.7.2.2. 提交事务

此流程演示了如何使用 Jakarta Transactions 进行交易。

先决条件

您必须先开始事务,然后才能提交。有关如何开始交易的详情,请参考 开始交易

  1. UserTransaction 调用 commit() 方法。

    当您在 UserTransaction 上调用 commit()方法时,TM 会尝试提交事务。

    @Inject
    private UserTransaction userTransaction;
    
    public void updateTable(String key, String value) {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        try {
            userTransaction.begin();
            <!-- Perform some data manipulation using entityManager -->
            ...
            // Commit the transaction
            userTransaction.commit();
        } catch (Exception ex) {
            <!-- Log message or notify Web page -->
            ...
            try {
                userTransaction.rollback();
            } catch (SystemException se) {
                throw new RuntimeException(se);
            }
            throw new RuntimeException(ex);
        } finally {
            entityManager.close();
        }
    }
    Copy to Clipboard Toggle word wrap
  2. 如果使用容器管理事务(CMT),则不需要手动提交。

    如果将 Bean 配置为使用容器管理交易,则容器将根据您在代码中配置的注解来管理您的事务生命周期。

    @PersistenceContext
    private EntityManager em;
    
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void updateTable(String key, String value)
      <!-- Perform some data manipulation using entityManager -->
      ...
    }
    Copy to Clipboard Toggle word wrap

结果

您的数据源提交和您的事务终止,或者抛出异常。

注意

有关完整示例,请参阅 Jakarta Transactions 交易示例

11.7.2.3. 回滚事务

此流程演示了如何使用 Jakarta Transactions 回滚事务。

先决条件

您必须先开始事务,然后才能回滚。有关如何开始交易的详情,请参考 开始交易

  1. UserTransaction 上调用 rollback() 方法。

    当您在 UserTransaction 上调用 rollback() 方法时,TM 会尝试回滚事务并将数据返回到之前的状态。

    @Inject
    private UserTransaction userTransaction;
    
    public void updateTable(String key, String value)
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        try {
            userTransaction.begin():
            <!-- Perform some data manipulation using entityManager -->
              ...
              // Commit the transaction
            userTransaction.commit();
        } catch (Exception ex) {
            <!-- Log message or notify Web page -->
            ...
            try {
                userTransaction.rollback();
            } catch (SystemException se) {
                throw new RuntimeException(se);
            }
            throw new RuntimeException(e);
        } finally {
            entityManager.close();
        }
    }
    Copy to Clipboard Toggle word wrap
  2. 如果使用容器管理事务(CMT),则不需要手动回滚事务。

    如果将 Bean 配置为使用容器管理交易,则容器将根据您在代码中配置的注解来管理您的事务生命周期。

注意

如果抛出 RuntimeException,则 CMT 会出现回滚。您还可以显式调用 setRollbackOnly 方法以获取回滚。或者,将 @ApplicationException(rollback=true)用于回滚应用异常。

结果

您的事务由 TM 回滚。

注意

有关完整示例,请参阅 Jakarta Transactions 交易示例

11.7.3. 在交易中处理 Heuristic Outcome

启发式事务结果不常见,通常具有特殊的原因。神秘一词意味着"手动",这就是通常必须处理这些结果的方式。有关启发式事务结果的更多信息,请参阅关于 Heuristic Outcomes

此流程演示了如何使用 Jakarta Transactions 处理交易的启发式结果。

  1. 事务中的启发式成果的原因是资源经理承诺可以提交或回滚,然后无法履行承诺。这可能是因为第三方组件、第三方组件和 JBoss EAP 之间的集成层或 JBoss EAP 本身存在问题。

    目前,导致启发式错误的最常见两个原因是环境中的瞬态故障,以及处理资源管理器的编码错误。

  2. 通常,如果您的环境中出现瞬态故障,您通常会在发现启发性错误前了解它。这可能是因为网络中断、硬件故障、数据库故障、电源中断或许多其他因素造成的。

    如果在压力测试期间测试环境中发现了启发性的结果,这意味着您的测试环境存在缺点。

    警告

    JBoss EAP 自动恢复出现故障时处于非修复状态的交易,但不试图恢复启发式交易。

  3. 如果您的环境中没有明显失败,或者启发式结果很容易再现,这可能是因为编码错误。您必须联系第三方供应商,以确定解决方案是否可用。

    如果您怀疑问题在 JBoss EAP 本身的交易经理中,您必须提交支持票据。

  4. 您可以使用管理 CLI 尝试手动恢复事务。如需更多信息,请参阅在 JBoss EAP 上管理交易的 恢复事务 参与者 一节。
  5. 手动解决事务结果的过程取决于故障的确切情况。根据您的环境执行以下步骤:

    1. 确定涉及哪些资源管理器。
    2. 检查事务管理器和资源管理器的状态。
    3. 在一个或多个涉及的组件中手动强制进行日志清理和数据协调。
  6. 在测试环境中,或者如果您不关注数据的完整性,请删除事务日志并重新启动 JBoss EAP 将会去除启发式结果。默认情况下,事务日志位于单机服务器的 EAP_HOME/standalone/data/tx-object-store/ 目录中,或者位于受管域中的 EAP_HOME/domain/servers/SERVER_NAME/data/tx-object-store/ 目录中。对于受管域,SERVE R_NAME 是指参与服务器组的单个服务器的名称。

    注意

    事务日志的位置还取决于使用的对象存储,以及为 object-store- relative-to 和 object-store -path 参数设置的值。对于文件系统日志,如标准 shadow 和 Apache ActiveMQ Artemis 日志,将使用默认的目录位置,但在使用 JDBC 对象存储时,事务日志存储在数据库中。

11.7.4. Jakarta Transactions 事务错误处理

11.7.4.1. 处理事务错误

事务错误很难解决,因为它们通常依赖于时间。以下是排除错误的一些常见错误和观点:

注意

这些规则不适用于启发性错误。如果您遇到启发性错误,请参阅 在交易中处理 Heuristic Outcome,并联系红帽全球支持服务以获得帮助。

事务超时,但业务逻辑线程未注意到

当 Hibernate 无法获取用于延迟加载的数据库连接时,这种类型的错误通常会列出自身。如果频繁发生,您可以延长超时值。有关 配置事务管理器 的详情,请查看 JBoss EAP 配置指南

如果这不可行,您或许能够调整外部环境以更快地执行,或者将代码重组为更高效。如果您遇到超时问题,请联系红帽全球支持服务。

事务已在线程上运行,或者您收到 NotSupportedException 异常

NotSupportedException 异常 通常表示您试图嵌套 Jakarta Transactions 事务,且不受支持。如果您没有尝试嵌套事务,则可能会在线程池任务中启动另一个事务,但无需暂停或终止事务即可完成任务。

应用通常使用 UserTransaction,后者自动处理此问题。如果是这样,则框架可能存在问题。

如果您的代码确实 直接使用 事务 管理器 或交易方法,请注意提交或回滚事务时的以下行为:如果您的代码使用 TransactionManager 方法来控制您的事务,则提交或回滚事务会从当前线程中解除事务关联。但是,如果您的代码使用 事务 方法,则事务可能不会与正在运行的线程关联,而且您需要手动将其从线程中取消关联,然后再将其返回到线程池。

您无法获取第二个本地资源
如果您尝试将第二个非 XA 资源放入事务中,则会出现这个错误。如果您在事务中需要多个资源,则必须是 XA。
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat