我有一个简单的EJB无状态类,有两个方法,都没有@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创建了新事务,第二个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();
}
这样,您应该获得预期的结果。但是您的一种假设并不完全正确。当您从saveAndThrowException
调用testTransacion
不是EJB调用时,这只是一个本地方法调用,如果您为@TransactionAttribute
声明了不同的saveAndThrowException
则无关紧要。
如果需要从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
}
无法发表评论,信誉不足。因此,有单独的帖子。
Areus的观点。调用的方式只是本地调用,因此,从外部调用时,在saveAndThrowException周围执行的所有拦截器都会被应用程序服务器省略。在将控制权返回给应用程序服务器之前,引发异常并直接捕获它。应用程序服务器对异常一无所知,因此,ergo erverything很好,并且事务已提交。