事务回滚后调用非事务方法

Calling non-transactional method after transaction is rolled back

我刚刚发现了一些 EJB 行为,这让我感到很吃惊。

这是代码示例(确保 MyBean、beanA、beanB 是使用 CMT 的 EJB):

@Stateless
public class MyBean {
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void myMethod(){
         try {
             beanA.methodA(); /* annotated as REQUIRED */
         } catch (Exception e) {
             beanB.methodB(); /* annotated as NOT_SUPPORTED */
         }
    }
}

假设 methodA 的执行时间超过事务超时时间,因此一旦它 returns myMethod 收到 TransactionRolledbackException,然后在 "myMethod" 中成功捕获。

我希望 "methodB" 到目前为止被调用,因为根据 EJB 规范,它必须在没有任何事务上下文的情况下被调用。 但实际上,"beanB"代理只是returns另一个TransactionRolledbackException,"methodB"没有执行。

纵观 EJB 规范,我没有看到任何证据证明容器应该或什至可能会那样做。

我错过了什么吗?任何提示将不胜感激。

更新

至少对于 Websphere,此行为似乎是特定于超时的。例如,当 "methodA" 抛出 RuntimeException 时设置的 "rollbackOnly" 标志不会阻止 "methodB" 执行。只有超时标志可以。

EJB 规范没有专门针对这种情况,只是指出一旦事务被标记为回滚,那么“继续事务是没有结果的”,并且对于NOT_SUPPORTED 的处理,规范指出它“ 没有规定容器应该如何管理具有未指定事务上下文的方法的执行”。

所有版本的 WebSphere Application Server 都采用了这样的方法,即处理 EJB 方法被标记为仅回滚的情况的最佳方法是防止容器控制的所有进一步操作,以便事务可能尽快回滚,确保及时释放资源(如数据库锁)。允许调用 NOT_SUPPORTED EJB 方法将导致标记为回滚的事务被挂起;从而继续持有可能阻止或已经阻止其他交易的资源。出于这个原因,WebSphere 会阻止这样的 activity.

不久前遇到过类似的问题。当容器将事务标记为回滚时,之后您将无法进行任何其他 EJB 调用。可以考虑为 beanA.methodA() 注解 @RequiresNew 的解决方案,这样它就不会共享 myMethod() 的全局事务,并且始终使用新事务。因此,这个新事务发生的任何事情都不会影响全局事务,因此您可以继续进行进一步的 EJB 调用。