【问题标题】:Java EE Transactional Type across various types of Beans跨各种 Bean 的 Java EE 事务类型
【发布时间】:2018-05-09 13:30:00
【问题描述】:

考虑以下场景:

无状态注释类ClassOne

@Stateless
public class ClassOne {
    // some injected fields
    // ....
    @Inject
    private ClassTwo classTwo;
    // ....

    public void methodInClassOne() {
        try {
            classTwo.methodInClassTwo();
        } catch(Exception e) {
            // handle exception
        }
    }
}

无状态注释类ClassTwo

@Stateless
public class ClassTwo {
    // some injected fields
    // ....
    @Inject
    private ClassThree classThree;
    // ....

    public void methodInClassTwo {
        try{
            classThree.methodInClassThree();
        } catch (Exception e) {
            // handle exception
        }
    }
}

非注解类ClassThree

public class ClassThree {
    // some injected fields
    // ....

    public void methodInClassThree {
        // some business logic
        // ....
        if (conditionCheck) {
            throw new RuntimeException("error message");
        }
    }
}

比如说,对于这种情况,上面的 conditionCheck 总是评估为 true。这是截至今天的工作代码。 RuntimeException 被包装在 EjbException 中,并按预期捕获、处理和重新抛出,直到它到达 ClassOne 的 catch 块。但是,当我使 ClassThree 无状态(使用@Stateless)时,被捕获的 RuntimeException 变成了 EjbTransactionRolledBackException,导致事务被回滚,并且 ClassOne 中任何尝试调用持久服务的处理都因此而崩溃。 我尝试使用 @TransactionAttributes 进行试验:

  1. 支持,必需 -> 提供相同的回滚行为终止事务

  2. NOT_SUPPORTED -> 甚至在条件检查之前,在 JpaRepository 调用上给出一个 TransactionRequiredException (我假设应该有一个带有原始非注释类的 TransactionType。而且可能不是同一个 Transaction就像在 ClassTwo 中一样 - 由于第 1 点。)

  3. REQUIRES_NEW -> 似乎与原始代码的行为相同。

我的印象是,如果没有明确说明,那么调用的方法/类将使用默认类型 REQUIRED(显然不是这种情况,因为如第 1 点所述)。那么 TransactionType 在 Annotated(EJB)-NonAnnotated(CDI) bean 之间是如何工作的呢?它与两个 Annotated(EJB) bean 之间的工作方式不同吗?我不确定我的问题是否清楚。简而言之,整个 Transaction 行为令人困惑,尤其是因为 ClassThree 在使其成为无状态之前和之后的行为方式不同。

对此的更多信息的任何输入或参考都会非常有帮助。提前致谢

【问题讨论】:

  • 我不认为它是带注释的 vs 未注释的,而是(就像你的标题暗示的那样,以及添加的 cdi 标记)EJB 与 CDI bean
  • 是的,它是 EJB(前两个类)与 CDI(第三类)。对困惑感到抱歉。我有兴趣了解事务在两个 EJB bean 之间(我认为这很简单)以及在 EJB 和 CDI bean 之间(令人困惑的部分 - 如上所述,行为在我做出后立即改变) CDI bean 也是 EJB)
  • 你读过stackoverflow.com/questions/17838221/… 吗?在 EJB 与 CDI 中处理事务的默认方式之间存在重大差异。后者默认不参与/影响交易。

标签: jakarta-ee ejb cdi stateless-session-bean session-bean


【解决方案1】:

当您将@Stateless 添加到ClassThree 时,它会成为隐式事务并且(如您所说)以REQUIRED 的事务类型运行。

每个 EJB 调用都通过一个名义上的“边界”,在该边界处检查调用的安全凭证,并在需要时(除其他事项外)设置(新)事务。调用的结果在调用完成时通过相同的边界传回。

默认情况下*,如果调用结果是java.lang.RuntimeException,那么容器需要

  1. 将当前事务标记为回滚
  2. 将 RuntimeException 包装在 EJBException 中
  3. 重新抛出新的 EJBException

这一切都发生在穿越那个边界的路上。

因此,methodInClassTwo 捕获 EJBTransactionRolledbackExceptionEJBException 的子类。请注意,杀死您的事务的是第 1 步,而不是任何后续的异常处理。

如果methodInClassThree 被标记为REQUIRES_NEW 的事务类型,那么在进入方法边界时总是会创建一个新事务。任何先前存在的事务都被暂停。抛出 RuntimeException 的行为与上述相同,只是它是回滚的新事务。进入边界之前处于活动状态的事务保持不变并被恢复。

最后,如果methodInClassThree 被标记为NOT_SUPPORTED 的事务类型,则当前事务在边界处暂停,并在调用完成时恢复。由于没有活动事务而引发 RuntimeException,因此没有回滚。但无论如何你都不想要这种情况。

*您可以使用@javax.ejb.ApplicationException 修改此行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-30
    • 2012-10-19
    • 2017-01-30
    • 1970-01-01
    • 2015-07-29
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    相关资源
    最近更新 更多