但是,這有一個問題。 在我看來,異常是第二個最常見的異常(在NullPointerException之后),即LazyInitializationException。 問題在于會話通常為您的服務層打開,并且在您將實體返回到視圖層后立即關閉。 當您嘗試在視圖中迭代未初始化的集合時(例如jsp),該集合將引發LazyInitializationException,因為它們所擁有的引用所在的會話已經關閉,并且無法獲取這些項。
如何解決? 所謂的OpenSessionInView / OpenEntityManagerInView“模式”。 簡而言之:您可以創建一個過濾器,以在請求啟動時打開會話,并在呈現視圖后(而不是在服務層完成后)關閉會話。 有人稱其為反模式,因為它將持久性處理泄漏到視圖層,并使設置復雜化。 我不會說那么糟糕:通常,它可以解決問題而不引入其他問題。 但是在我參與的所有最新項目中,我們沒有使用OpenSessionInView,而且效果很好。
之所以能正常工作,是因為我們沒有使用惰性集合。 但是,您會正確地指出,當您加載單個實體時,您將獲取“整個世界”。 好吧,不。 * ToMany映射有兩種類型:
- 值類型映射,集合在邏輯上不包含十幾個元素。 在大多數情況下,這是@ElementCollection,還有@ * ToMany,它們帶有諸如“ Category”或“ Price”之類的項,它們只是更復雜的值對象,但自身不包含任何其他映射。 這些類型的集合的另一個共同特征是它們通常與它們自己的實體一起顯示在UI中。 例如,您最有可能要顯示文章的類別。 對于這種類型的集合,EAGER是更好的選擇。 無論如何,您都必須獲取它們,為什么不讓休眠(或任何jpa實現)想到一些巧妙的連接呢? 就像我說的那樣-邏輯上集合不超過一打或十二個,因此獲取它們不會對性能造成影響。 而且,從邏輯上講,它們不會與它們一起獲取大對象圖。
- 大型核心實體之間的映射。 可以是“用戶所下的所有訂單”或“組織中的所有用戶”,“供應商的所有項目”等。您當然不想急于獲取它們。 因為如果您為一個組織獲取2000個用戶,那么每個組織又有1000個訂單,而一個訂單平均有3個項目,這反過來又包含所有購買該項目的人的集合。.您將最終擁有整個數據庫在記憶中。 顯然您需要惰性集合,對嗎? 好吧,不。 在這種情況下,您根本不應該使用集合映射。 在99%的情況下,這些類型的關系顯示在UI的頁面列表中。 或在搜索結果中。 它們永遠不會(也永遠不會)全部顯示在一個屏幕上(或者,如果您的應用程序提供了類似REST API之類的東西,則很少應該在一個API調用中返回它們)。 您必須對其進行查詢,并使用query.setMaxResults和query.setFirstResult()(或使用一些限制性條件來限制它們)。 此外,對集合進行映射意味著有人會在某個時候嘗試使用它們,這可能會失敗。 并且如果對象已序列化(xml,json等),則將獲取集合內容。 您幾乎肯定不想發生的事情。 (這里的想法草案:JPA可以有一個PagedList集合,該集合將允許分頁的延遲提取,從而消除了查詢的需要)
所以我剛才說的是-永遠不要使用惰性集合。 將eager集合用于非常簡單的淺表映射,將分頁查詢用于較大的映射。
好吧,不完全是。 延遲集合在那里并且它們有應用,盡管它是相當有限的。 或者,至少它們比所使用的方法不太適用。 這是我發現適用的示例場景。 在我的附帶項目中,我有一個Message實體,并且它包含一個Picture實體的集合。 用戶上載圖片時,它將存儲在該集合中。 一條消息最多可以包含10張圖片,因此非常希望收藏。 但是,然后,Message是最常用的實體–實際上是在每個請求中獲取的。 但是只有一些消息帶有圖片(您的信息流中有多少條推文有圖片上傳?)。 因此,我不想讓休眠狀態進行查詢只是為了查找給定消息沒有圖片。 因此,我將圖片數量存儲在一個單獨的字段中,使圖片集合變得懶惰,并且僅在圖片數量> 0時才手動對其進行Hibernate.initialize(..)。
因此,在某些情況下,當實體具有屬于上述第一類的可選集合時(“小型淺表集合”)。 因此,如果它很小,很淺并且是可選的(例如,在不到20%的情況下使用),則應該使用Lazy來保存不必要的查詢。
其他方面–懶惰的收藏會讓您的生活更艱難。
參考:在Bozho的技術博客上, 避免與我們的JCG合作伙伴 Bozho一起使用懶惰的JPA Collections 。
相關文章 :
- 休眠陷阱
- DataNucleus 3.0與Hibernate 3.5
- Hibernate映射集合性能問題
- ORM問題
- 框架使開發人員愚蠢嗎?
- 每個程序員都應該知道的事情
- Java最佳實踐
翻譯自: https://www.javacodegeeks.com/2011/10/avoid-lazy-jpa-collections.html