2011-05-17 50 views
0

我有一個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()拋出異常(因爲事務由容器管理)。

回答

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。

+0

還必須重新配置ejb-jar.xml文件,其中(至少在我的情況下)指定了EJB事務類型。 – miha 2011-05-18 06:08:13

+0

是的,如果您使用的是ejb-jar.xml而不是註釋,則需要更新XML以指定事務類型。 – 2011-05-18 14:47:07

1

我不是EJB方面的專家,但我一直在處理幾天的JPA和事務。

我最近回答了關於實體如何在上下文中駐留的另一個問題,以及它如何在Java EE應用程序中工作,上下文與您的JTA事務相關聯。

通過點擊here可以查看此答案的詳細信息。我認爲理解上下文的作用以便理解你所描述的問題的性質是有用的。

如果不提供交易支持,那麼沒有什麼堅持從容器的角度來看,因此,你對環境的變化是暫時的

此外,您必須考慮一旦發生異常,您的上下文將變爲無效,並且其中的實體會分離。 (有一些例外,如NoResultException)。

因此,從這一點開始,如果您想提交某些內容,您需要一個新的JTA事務和一個新的JPA上下文,以便能夠提交對數據庫的更改。如上所述,我不是EJB專家,但是如果您的方法由於異常而失敗,並且您仍然希望通過重新調用該方法來再次重試該事務,那麼您可以強制一個新事務成爲在每次調用方法時創建,由此創建一個新的新JPA上下文。另一方面,如果您希望對實體進行修改而不管該方法是否存在異常,那麼您可能會考慮將正在更新實體的代碼移至定義爲啓動的新EJB方法中每次調用它時新的事務(TransactionAttributeType.REQUIRES_NEW)。

當第二個內部方法結束時,無論您的EJB失敗的外部方法如何,您對事務的處理都將自動刷新到數據庫。

基本上,您將爲您的實體提供新的上下文,並將此上下文鏈接到新事務,並在內部方法完成時提交作用域。

據我瞭解,EJB容器中的自然行爲是永遠的方法會加入已經存在的事務,這就是我想要阻止的事情。另一種選擇:如果你想使用不同的事務支持來控制你的上下文,那麼你可能會考慮提供一個基於資源本地的持久化單元,你可以手動實例化你的實體管理器並控制事務範圍。但說實話,這對我來說聽起來不是一個好主意,至少在你描述的問題的背景下沒有。