2011-03-21 73 views
0

說我有以下部署爲本地SLSB通用的DAO:應該在EJB 3.0 DAO中使用em.flush來抽象持久層?

public interface CrudService { 

public <T> T create(T t); 

public <T> T find(Object id, Class<T> type); 

public <T> T update(T t); 

public void delete(Object t); 

public List<Object> findByNamedQuery(String queryName); 

public List<Object> findByNamedQuery(String queryName, int resultLimit); 

public List<Object> findByNamedQuery(String namedQueryName, Map<String, Object> parameters); 

public List<Object> findByNamedQuery(String namedQueryName, Map<String, Object> parameters, int resultLimit); 

}

這DAO是從許多其他SLSB服務使用。我想從業務邏輯中抽象出整個持久層(所有操作和異常)。我創建了@AroundInvoke方法攔截像下面,把它放在DAO的類層次:

@AroundInvoke 
public Object wrapExceptions(InvocationContext context) throws Exception { 
    try { 
      return context.proceed();   
    } catch(Exception e) { 
       throw mapToApplicationException(e) 
    } 
} 

沒有異常被捕獲,並因此映射具有DAO方法的默認實現。 但是如果我在持久化結束時使用flush,更新和刪除它的工作方式 - 那沒關係。

現在我的問題是:它是唯一能讓它工作的方法嗎?我知道調用flush是相當沉重的,如果我需要打電話讓我們說更新多次,這將是一個嚴重的瓶頸。

編輯: 另一種選擇是使用BMT,但它會導致與tx.begin()等被污染的所有門面方法......克里斯·巴比奇答案後

編輯:

我根據克里斯的提議有些疑問。處理服務層中的PersisteceExceptions會導致混合圖層透明度。但這對我來說並不是最糟糕的。假設我有服務門面使用我的服務或DAO集。服務門面方法需要在自己的事務上執行,所以我會使用CMT並用@TransactionAttribute(REQUIRES_NEW)標記它。這樣做沒有地方可以有異常處理點(攔截器不起作用,因爲交易仍在進行中 - 這與上述情況相同)。所以我看到兩種方法:要麼有所有的外觀方法使用BMT並處理所有的tx.begin(),tx.commit()等東西,要麼有另一個「Facade for Facade」擁有@TransactionAttribute(從不),然後調用交易門面和處理它是例外。

+0

記住生命週期攔截器不需要在服務本身中定義。您希望將常見攔截邏輯(如錯誤處理)分離爲可應用於多個類,服務等的獨立攔截器類。此分隔可讓您將業務功能與標準異常之間的關注區分開來處理。 – 2011-03-24 22:08:59

+0

至於持久性異常與其他異常之間的區別,取決於異常處理的目標。你在乎什麼是例外情況或者發生了錯誤情況?您是試圖實現一個通用的錯誤處理框架,還是需要以不同的方式處理每種類型的錯誤?通過異常處理,您應該實現一個通用處理框架,並且只能手動處理需要處理的異常或需要應用程序更改其處理流程的異常。其餘的應該由你的錯誤框架自動處理。 – 2011-03-24 22:11:24

+0

也許我沒有說清楚。我的前夫。處理攔截器實際上是一個獨立的類。根據異常處理,我希望我的服務門面客戶端只處理除了所有javax.persistence.PersistenceException之外的自定義應用程序定義的異常。 – veilsoen 2011-03-25 08:30:29

回答

0

我想這一切都取決於你想要做什麼。如果您希望所有數據立即插入到數據庫中,並且可以立即使用該插入導致的任何問題,那麼您實際上只有兩種選擇:專門在EntityManager上調用flush(),這將導致所有批處理數據源操作成爲執行,或者指定一個事務以DAO方法開始和結束(這裏有不同的選項,但我不會在這裏進入)。這兩個選項都會對性能和成功的業務事務定義產生負面影響。

JPA實現中的一個特性就是PersistenceContext的概念。 PersistenceContext是一組被管理的實體。這些實體的生命週期由EntityManager管理。 EntityManager的部分職責是管理PersistenceContext的更改何時與數據源同步。 EntityManager可能會對PersistenceContext進行一些更改批處理,並在稍後的時間點(如在事務提交期間)同步它們。在這種情況下,如果將數據插入數據庫時​​出現問題,則可能會在稍後的某個時間才能看到異常。對em.flush()的調用會立即導致數據源同步,從而引發數據庫插入期間可能發生的任何異常。

異常處理的一個好方法是隻將它添加到需要它的地方。將它添加到拋出RuntimeExceptions的底層方法並不一定是一個好的候選者。如果想要添加一致的錯誤處理(例如轉換爲常見的RuntimeException),那麼您希望在公共入口點(例如業務層或類似的位置)執行此操作。這使您可以限制需要維護的異常處理總量,尤其是因爲錯誤實際上可能發生在應用程序中的任何位置。我還建議您在主要事務入口點處有異常處理,因爲這是您需要管理任何意外異常的地方,只有在事務提交期間纔會發生異常,特別是在使用樂觀鎖定時。

只是有些想法,希望他們幫助。

+0

非常感謝您的回答。我編輯了我的文章,對您的解決方案有一些想法。 – veilsoen 2011-03-24 10:06:26