0

考虑以下场景:

无状态注释类 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. SUPPORTS, REQUIRED -> 给出相同的 RollBack 行为来终止事务

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

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

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

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

4

1 回答 1

0

当您添加它时@StatelessClassThree它会成为隐式事务,并且(如您所说)的事务类型为REQUIRED)。

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

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

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

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

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

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

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

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

于 2018-05-15T13:52:52.970 回答