2013-03-06 16 views
1

我在長時間運行的對話(使用JPA /休眠和Seam 2.2)中第一級緩存存在問題。如何避免長時間運行Seam對話中的一級緩存

我們有一個搜索頁面,使用長時間運行的對話(需要一些Ajax交互,編輯模態等)。

問題是,當另一個用戶更改實體時,當用戶再次單擊搜索按鈕時,更改不會顯示。 見similar problem here

那麼長時間運行的對話實體從1級高速緩存加載過程中,在其它事務中做出的更改不會被加載,除非你手動調用每個實體刷新。

我試過使用CacheMode.IGNORE或CacheMode.REFRESH(通過hibernate查詢),但沒有解決問題,因爲它只處理二級緩存。

我可以看到選擇查詢被髮送到數據庫,但看起來Hibernate仍然使用第一級緩存中的緩存對象。

我試圖從我以前的搜索中驅逐實體,然後再進行新的搜索,然後運行,但是後來我遇到了有線問題,因爲會話中仍有對象指向現在被驅逐的實體。 您必須添加

@org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.EVICT,org.hibernate.annotations.CascadeType.REFRESH}) 
你的實體關係

但很容易錯過一個。

您也可以清除空洞會話,但這可能會導致LazyInitializationErrors。

是不是有辦法告訴JPA/Hibernate不要在查詢中使用第一級緩存?

編輯:有一個Good answer爲什麼它不起作用,但刷新每個實體的建議並不理想。我以前使用過這個,但問題在於,例如對於200個條目的列表,您可以爲數據庫生成200個單獨的負載,這使得它非常緩慢。 這200個條目中只有一兩個可能已經改變! 那麼你如何識別哪些實體已經改變!我猜如果你在每次更改的實體上使用時間戳,你可以使用它。只需記錄先前搜索的時間戳,然後搜索列表中已發生更改的實體。你怎麼看,那裏有更優雅的解決方案?

回答

3

解決此問題的方法可能是在EVENT範圍中定義單獨的持久性上下文工廠,並將其用於查詢。在components.xml

<persistence:managed-persistence-context scope="event" auto-create="true" 
    entity-manager-factory="#{yourfactory}" name="eventScopedEM" /> 

這樣做是在每一頁上的事件創建一個新的實體管理器,而不是保持相同的實體管理器在整個談話。保留其他會話範圍的持久化上下文工廠(默認爲#{entityManager})以用於所有其他用途。如果使用EntityQuery組件查詢,請記得設置實體管理器的名稱(否則它默認爲entityManager),覆蓋getPersistenceContextName()方法(對於基於Java的查詢組件)或顯式設置實體管理器(對於基於xml的查詢組件),例如:

<framework:entity-query entityManager="#{eventScopedEM}"> 
    <framework:ejbql>from MyEntity</framework:ejbql> 
    ... 
</framework:entity-query> 
+0

這是一個有趣的解決方案!當然,使用兩個實體管理器時,您不必使用一個entityManager加載的實體與另一個entityManager一起使用,那麼您需要非常小心。 – Ben 2013-04-04 14:19:18

+0

我已經避免了上面的問題,只需遍歷列表並將其合併到「普通」entityManager中即可。我第一次運行查詢時,使用普通的對話範圍的entityManager。在隨後的搜索中,我使用事件範圍的entityManager,然後遍歷列表並在普通eventManager上合併實體。如果使用事件範圍化的entityManager並僅在後續搜索中進行合併,它會將合併開銷保持在最低水平。需要更多的測試,但看起來很有希望 – Ben 2013-04-04 15:30:16

相關問題