EJB 3.1 TransactionAttributeType.REQUIRES_NEW and setRollbac



请帮助我了解EJB 3.1中的事务。我正在使用GlassFish v3,并出现以下情况:

@Stateless
@LocalBean
public class BeanA {
    @Inject BeanB bean; /* which has no TransactionAttribute set */
    @Resource SessionContext context;
    public void run() {
        ...
        for (...) {
            process(someValue);
        }
    }
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(String someValue) {
        try {
            SomeEntity entity = bean.getEntity(someValue);
            entity.setSomeProperty("anotherValue");
            ...
        } catch(CustomException e)  {
            this.context.setRollbackOnly();
        }
    }
}

BeanA.run是从servlet中调用的。我想把每个迭代都当作一个单独的事务处理。我以为使用TransactionAttributeType.REQUIRES_NEW会实现这一点,但在调用setRollbackOnly之后,我在beanB上的后续迭代中得到了javax.ejb.EJBTransactionRolledbackException。奇怪的是,当我把run()以外的所有东西都移到一个新的BeanC并调用BeanC.process时,它确实起作用了。我错过了什么?有人能解释一下为什么会这样吗?

编辑:仔细想想:这是因为容器不拦截对同一EJB中方法的调用吗?

编辑2:是的,在这里找到了答案:本地方法调用中的EJB事务(我必须知道答案才能找到:)

在这里找到了答案:本地方法中的EJB事务调用

简而言之:容器不拦截本地方法调用,因此setRollbackOnly标记了回滚的唯一事务,解释了异常情况。

老问题,但为了完整性。。。

事实上,像@TransactionAttribute这样的注释在类中直接调用时不会被处理。发生这种情况是因为,您直接调用它,就像在过程函数中一样。它不经历EJB生命周期(包括拦截器)。

不过还是有办法的。您需要注入self类并使用该引用:

// Bean A
@Resource SessionContext context;
public void run() {
    ...
    for (...) {
       context.getBusinessObject(BeanA.class).process(someValue);
    }
}

通过这种方式,它将创建进程@TransactionAttribute
虽然它有效,但我不确定这是否是一个好的设计。

最新更新