我有一个EJB,其方法(除其他外)保留了JPA实体。如果该方法抛出错误,则回滚事务并且不保留实体。
但是,我做希望持久化该实体,而不管EJB方法中可能出现的任何异常。
我正在使用WebSphere 7.0,EJB3.0,JPA 1.0(在WAS中的OpenJPA),DB2,如果它很重要。
我尝试在EJB之上设置@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
;即使没有例外,实体也不会持久存在。我也尝试过自己提交事务(em.getTransaction()。commit()),但getTransaction()抛出异常(因为事务由容器管理)。
答案 0 :(得分:2)
使用bean管理的事务。
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class MyEJB {
@PersistenceContext(unitName="...")
private EntityManager _em;
@Resource
private UserTransaction _utx;
public void myEJBMethod() {
_utx.begin();
// Use _em
_utx.commit();
// Do other work that might throw an exception.
}
}
或者,按照edalorzo的建议使用TransactionAttributeType.REQUIRES_NEW。
答案 1 :(得分:1)
我不是EJB的专家,但我现在已经处理了几天的JPA和交易。
我最近回答了另一个关于实体如何驻留在上下文中的问题,以及它如何在Java EE应用程序中工作,上下文与您的JTA事务相关联。
点击here即可查看此答案的详细信息。我认为理解上下文的工作原理是有用的,以便理解你所描述的问题的本质。
如果您不提供交易支持,那么从容器的角度来看没有任何内容可以坚持,因此,您对上下文的更改是暂时的。
此外,您必须考虑一旦发生异常,您的上下文将变为无效,并且其中的实体将被分离。 (这有一些例外,比如NoResultException)。
因此,从那时起,如果你想提交一些东西,你需要一个新的JTA事务,带有一个新的JPA上下文,以便能够提交对数据库的更改。
正如我所说,我不是EJB的专家,但是如果你的方法由于异常而失败并且你仍然希望通过重新调用该方法再次重试该事务,那么你可以强制创建一个新的事务每次调用该方法时,您都会创建一个新的JPA上下文。
另一方面,如果您希望对实体的修改保持不变,无论方法中是否有异常,那么您可能会考虑将更新实体的代码移动到定义为启动的新EJB方法每次调用它时都有新事务(TransactionAttributeType.REQUIRES_NEW)。
当第二个内部方法完成时,无论EJB的外部方法失败,您对事务的处理都将自动刷新到数据库。
基本上,您将为实体提供新的上下文,并将此上下文链接到新事务,并在内部方法完成时作出提交作用。
据我所知,EJB容器中的自然行为是,任何方法都会加入已存在的事务,从我的角度来看,这是您可能想要阻止的事情。
另一种选择:如果您想使用不同的事务支持来控制上下文,那么您可能会考虑提供基于资源本地的持久性单元,您可以手动实例化实体管理器并根据需要控制事务范围。但老实说,这对我来说听起来不是一个好主意,至少在你描述的问题的背景下没有。