在同一个 EJB 中调用方法时的事务传播

Transaction propagation when calling methods inside the same EJB

我有一个简单的 EJB 无状态 class,它有两个方法,都没有 @TransactionAttribute。第一个方法保存啤酒并调用另一个保存其他啤酒并抛出异常的方法。

@Stateless
public class EJBContainer {

    @PersistenceContext
    EntityManager em;

    public void testTransaction() {
        em.persist(getBeer("Corona"));
        try {
            saveAndThrowException();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void saveAndThrowException() {
        em.persist(getBeer("Heineken"));
        throw new RuntimeException();
    }

    //getBeer() definition
}

我假设这两种方法都将使用默认交易类型(必需)- 因此将在第一种方法中创建一个新交易,并将在第二种方法中使用它。因此抛出异常应该回滚此事务,并且 EntityManager 不会保存任何啤酒。但事实证明,两瓶啤酒都得救了。我哪里错了?

当我将第二个方法移动到另一个无状态 EJB 时,它按我预期的那样工作 - 第一个 EJB 创建了新事务,第二个使用了它,异常导致回滚并且没有保存任何啤酒。

从这个 JAX-RS 客户端调用 EJB:

@ApplicationScoped 
public class BeerController { 

    @Inject 
    private EJBContainer ejbContainer; 

    @POST 
    public void addBeer() { 
        ejbContainer.testTransaction(); 
    } 
}

由于您使用的是无界面视图,注入可能无法正常工作。我会尝试使用 @EJB 注释而不是 @Inject.

@EJB 
private EJBContainer ejbContainer; 

@POST 
public void addBeer() { 
    ejbContainer.testTransaction(); 
}

这样你应该会得到预期的结果。但是您的假设之​​一并不完全正确。当您从 testTransacion 调用 saveAndThrowException 不是 EJB 调用时,它只是本地方法调用,如果您为 saveAndThrowException 声明了不同的 @TransactionAttribute if 则无关紧要。

如果您需要从 EJB 的另一个事务方法调用事务方法,您可以添加对 EJB 本身的引用,然后像调用另一个 EJB 一样调用它:

@Stateless
public class EJBContainer {

    @PersistenceContext
    EntityManager em;

    @EJB
    private EJBContainer ejbContainer;

    public void testTransaction() {
        em.persist(getBeer("Corona"));
        try {
            ejbContainer.saveAndThrowException();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void saveAndThrowException() {
        em.persist(getBeer("Heineken"));
        throw new RuntimeException();
    }

    //getBeer() definition
}

还不能发表评论,声望不够。因此单独 post.

阿瑞斯说的有道理。您调用它的方式只是本地调用,因此应用程序服务器省略了从外部调用它时执行的所有围绕 saveAndThrowException 的拦截器。您抛出异常并在将控制权返回给应用程序服务器之前直接捕获它。应用程序服务器对异常一无所知,因此一切正常,事务已提交。