跨各种类型的Bean的Java EE Transactional Type

时间:2018-05-09 13:30:01

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

考虑以下情况:

无状态注释类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,导致事务为Rolledback,并且尝试调用持久服务的ClassOne中的任何处理都会因此而爆炸。 我尝试过试验@TransactionAttributes:

  1. 支持,必需 - >提供相同的RollBack行为以终止交易

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

  3. REQUIRES_NEW - >这看起来像原始代码一样。

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

    任何输入或参考更多信息都会非常有用。提前致谢

1 个答案:

答案 0 :(得分:0)

当您将@Stateless添加到ClassThree时,它会隐式进行交易,并且(正如您所说)行为类型为REQUIRED)。

每个EJB调用都通过一个名义上的边界"检查呼叫的安全凭证,并在需要时设置(新)交易(除其他外)。调用结束时,调用的结果将通过相同的边界传回。

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

  1. 标记当前事务以进行回滚
  2. 将RuntimeException包装在EJBException中
  3. 重新抛出新的EJBException
  4. 这一切都发生在通过该边界的路上。

    因此,methodInClassTwo会抓住EJBTransactionRolledbackExceptionEJBException的子类。请注意,第1步会终止您的交易,而不是任何后续的异常处理。

    如果methodInClassThree标记了事务类型REQUIRES_NEW,则在进入方法边界时始终会创建新事务。任何先前存在的交易都将暂停。抛出RuntimeException的行为如上所述,除了它是回滚的新事务。在进入边界之前处于活动状态的交易保持不变并恢复。

    最后,如果methodInClassThree标记为事务类型NOT_SUPPORTED,则当前事务将在边界处暂停,并在呼叫完成时恢复。由于没有活动事务,因为抛出RuntimeException而没有回滚。但是你无论如何都不想要这个场景。

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