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")
    • 使用注入获取实例。

      @Resource UserTransaction userTransaction;
    • 使用 Jakarta Enterprise Beans 上下文获取实例。

      • 在无状态/状态 Bean 中:

        @Resource SessionContext ctx;
        ctx.getUserTransaction();
      • 在消息驱动型 Bean 中:

        @Resource MessageDrivenContext ctx;
        ctx.getUserTransaction()
  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
            ...
        }
    }

结果

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

有关完整示例,请参阅 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();
        }
    }
  2. 如果使用容器管理事务(CMT),则不需要手动提交。

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

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

结果

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

注意

有关完整示例,请参阅 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();
        }
    }
  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

© 2026 Red Hat
返回顶部