即使 EJB 方法抛出异常,如何保留 JPA 实体?
我有一个 EJB,其方法(除其他外)保留 JPA 实体。如果该方法抛出错误,事务将回滚并且实体不会被持久化。
但是,我确实希望该实体能够持久保存,无论 EJB 方法中可能发生的任何异常如何。
我正在使用 WebSphere 7.0、EJB3.0、JPA 1.0(WAS 中的 OpenJPA)、DB2(如果有的话)。
我尝试在 EJB 之上设置 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
;这样,即使没有例外,实体也不会被持久化。我也尝试自己提交事务(em.getTransaction().commit()),但是 getTransaction() 抛出异常(因为事务是由容器管理的)。
I have an EJB, whose method (among other things) persists JPA entity. If the method throws an error, the transaction is rolled back and the entity is not persisted.
However, I do want that entity to be persisted regardless of any exceptions, that might occur in the EJB method.
I'm using WebSphere 7.0, EJB3.0, JPA 1.0 (OpenJPA that is in WAS), DB2, if it matters.
I tried setting @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
on top of EJB; with that, entity is not persisted even if there is no exception. I also tried commiting transaction myself (em.getTransaction().commit()), but getTransaction() throws exception (because transactions are managed by container).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用 Bean 管理的事务。
或者,按照 edalorzo 的建议使用 TransactionAttributeType.REQUIRES_NEW。
Use bean-managed transactions.
Alternatively, use TransactionAttributeType.REQUIRES_NEW as suggested by edalorzo.
我不是 EJB 方面的专家,但我已经处理 JPA 和事务几天了。
我最近回答了另一个问题,关于实体如何驻留在上下文中,以及它在 Java EE 应用程序中如何工作,上下文与 JTA 事务链接。
您可以通过单击 这里。我认为了解上下文如何工作以理解您所描述的问题的本质是有用的。
如果您不提供事务支持,那么从容器的角度来看,没有任何东西可以持久保存,因此,对上下文的更改是暂时的。
此外,您还必须考虑到,一旦发生异常,您的上下文就会变得无效,并且其中的实体会被分离。 (有一些例外,例如 NoResultException)。
因此,从那时起,如果您想要提交某些内容,则需要一个新的 JTA 事务和一个新的 JPA 上下文,以便能够向数据库提交更改。
正如我所说,我不是 EJB 方面的专家,但如果您的方法由于异常而失败,并且您仍然想通过重新调用该方法来重试事务,那么您可以强制每次创建一个新事务。方法被调用,由此,您将创建一个新的 JPA 上下文。
另一方面,如果您希望保留对实体的修改,无论方法中是否存在异常,那么您可能需要考虑将更新实体的代码移至定义为启动新事务的新 EJB 方法(每次调用 TransactionAttributeType.REQUIRES_NEW) 时。
当第二个内部方法完成时,您对事务所做的工作将自动刷新到数据库,无论 EJB 的外部方法是否失败。
基本上,您将为您的实体提供一个新的上下文,并将此类上下文链接到一个新的事务,其作用域是在内部方法完成时提交。
据我了解,EJB 容器中的自然行为是,任何方法都会加入已经存在的事务,而从我的角度来看,这正是您可能想要阻止的情况。
另一种选择:如果您想使用不同的事务支持来控制上下文,那么您可能需要考虑提供基于资源本地的持久性单元,并且您可以根据需要手动实例化实体管理器并控制事务范围。但老实说,这对我来说听起来不是一个好主意,至少在您描述的问题的背景下不是。
I am not an expert on EJBs, but I have been dealing with JPA and transactions for a few days now.
I recently answered another question about how entities resided in a context, and how this works in Java EE applications, the context is linked with your JTA transaction.
You can see details of this answer by clicking here. I think it is useful to understand how to context works in order to comprehend the nature of problems like the one you describe.
If you do not provide transaction support, then there is nothing to persist from the container standpoint, and therefore, your changes to the context are transient.
Also you have to consider that once an exception occurs, your context becomes invalid, and the entities in it get detached. (There are a few exceptions to this, like NoResultException).
Thus, from that point on, if you want to commit something, you need a new JTA transaction, with a new fresh JPA context in order to be able to commit changes to the database.
As I said, I am not an expert in EJBs, but if your method fails due to exceptions and you still would like to retry the transaction again by re-invoking the method, then you could force a new transaction to be created every time the method is invoked and by this, you would create a new fresh JPA context.
On the other hand, if you want your modifications to the entities to be persisted, regardless of exceptions in the method, then you might like to consider moving the code that is updating the entities to a new EJB method defined to start a new transaction (TransactionAttributeType.REQUIRES_NEW) every time you invoke it.
By the time this second inner method finishes, your work over the transactions will be automatically flushed to the database, regardless of the outer method of you EJB failing.
Basically, you would be providing a new context for your entities, and linking such context to a new transaction, scoped to commit when the inner method completes.
The natural behavior in EJB containers, as far as I understand, is that ever method joins the already existing transaction, and this is what you might like to prevent, from my point of view.
Another alternative: if you want to control your context using a different transaction support then you might like to consider providing a resource-local based persistence unit and you can manually instantiate your entity manager and control transaction scope as you wish. But honestly, this does not sound like a good idea to me, at least no in the context of the problem that you described.