使用PersistenceContextType.EXTENDED的有狀態EJB加載收集
該方法只能應用于與Full JEE環境兼容的應用程序:將EJB與PersistenceContextType.EXTENDED一起使用。
檢查下面的代碼,DAO的樣子:
package com.ejb;import javax.ejb.Stateful;
import javax.persistence.*;import com.model.Person;@Stateful
public class SystemDAOStateful {@PersistenceContext(unitName = 'LazyPU', type=PersistenceContextType.EXTENDED)private EntityManager entityManager;public Person findByName(String name) {Query query = entityManager.createQuery('select p from Person p where name = :name');query.setParameter('name', name);Person result = null;try {result = (Person) query.getSingleResult();} catch (NoResultException e) {// no result found}return result;}
}
public class DataMB {// other methods and attributes@EJBprivate SystemDAOStateful daoStateful;public Person getPersonByStatefulEJB() {return daoStateful.findByName('Mark M.');}
}
<h:dataTable var='dog' value='#{dataMB.personByStatefulEJB.lazyDogs}'><h:column><f:facet name='header'>Dog name</f:facet>#{dog.name}</h:column>
</h:dataTable>
這種方法的優點和缺點:
優點 | 缺點 |
容器將控制數據庫事務 | 僅適用于JEE |
模型類別將不需要編輯 | 可能會發生N + 1效應 |
大量的有狀態EJB可能會影響容器內存。 |
這種方法可能會產生N + 1效果,并且有狀態EJB的特征是在其會話未到期或丟失參考之前不會被刪除/銷毀。
警告 :在保留在Pool中的對象中保留對注入的EJB的引用不是一個好習慣。 JSF將創建一個ManagedBean池以更好地處理用戶請求。 必要時,容器將增加或減少池中ManagedBean的數量。 在本文的代碼中,假設如果容器在池中創建100個ManagedBeans實例,則服務器將在內存中容納100個有狀態EJB。 解決該問題的方法是對有狀態EJB進行JNDI查找。
通過聯接查詢加載集合
該解決方案易于理解和應用。
請參見下面的代碼:
public Person findByNameWithJoinFech(String name) {Query query = entityManager.createQuery('select p from Person p join fetch p.lazyDogs where p.name = :name');query.setParameter('name', name);Person result = null;try {result = (Person) query.getSingleResult();} catch (NoResultException e) {// no result found}return result;}
public Person getPersonByQuery() {return systemDAO.findByNameWithJoinFech('Mark M.');}
<h:dataTable var='dog' value='#{dataMB.personByQuery.lazyDogs}'><h:column><f:facet name='header'>Dog name</f:facet>#{dog.name}</h:column></h:dataTable>
這種方法的優點和缺點:
優點 | 缺點 |
數據庫中只會觸發一個查詢 | 每個訪問的集合/惰性屬性都需要一個查詢 |
模型類別將不需要編輯 | |
將只帶來所需的數據 | |
N + 1效果不會發生 |
這種方法的缺點是需要新的查詢來訪問每個模型類集合/惰性屬性。 如果只需要查詢“ Person”狗,則需要特定查詢。 假設我們需要查詢“個人”電子郵件,則有必要進行其他查詢。
這種方法可以應用于JSE和JEE。
EclipseLink和惰性集合初始化
關系的默認值為:
關系 | 取 |
@OneToOne | 急于 |
@OneToMany | 懶 |
@多多 | 急于 |
@多多多 | 懶 |
但是JPA Spec *指出:
EAGER策略是對持久性提供程序運行時的要求,必須熱切地獲取數據。 LAZY策略向持久性提供程序運行時提供了提示,即首次訪問數據時應延遲獲取數據。 該實現允許急切地獲取已為其指定LAZY策略提示的數據 。 特別是,懶惰獲取可能僅適用于使用基于屬性的訪問的基本映射。
如您在上面的文本中看到的那樣,JPA實現可能會忽略提示策略。 EclipseLink具有JEE行為和JSE其他行為。 您可以在此處查看每種行為: http : //wiki.eclipse.org/Using_EclipseLink_JPA_Extensions_%28ELUG%29#What_You_May_Need_to_Know_About_EclipseLink_JPA_Lazy_Loading
我們可以在互聯網上找到一些人說,即使是惰性集合,EclipseLink也會在加載實體時執行n + 1查詢。 我們可以找到使用Glassfish和EJB的用戶的這種行為。
在下面,您將看到一些在EclipseLink上正確使用延遲加載的提示:
- http://stackoverflow.com/questions/8490532/eclipselink-lazy-loading
- http://stackoverflow.com/questions/3932623/eclipselink-dont-fetch-some-fields-by-default
- https://forums.oracle.com/forums/thread.jspa?messageID=1706796
* JSR-000220企業JavaBeans 3.0最終版本(持久性)9.1.18,并將重復與水獺JPA的關系。
結束!
我認為最好的解決方案是聯接獲取查詢。 您可以根據自己的應用選擇最佳解決方案 。
單擊此處下載此帖子的源代碼 。 如果要運行本文的代碼,則需要創建一個名為LazyExceptionDB的數據庫和JBoss模塊。 附加到源代碼的是Postgres模塊。 如果您想了解如何設置數據源以及Postgres或MySQL模塊,則可以在這里查看: 完整的WebApplication JSF EJB JPA JAAS 。
希望這篇文章對您有所幫助。
如果您有任何意見或疑問,請發表。
再見。
參考: uaiHebert博客上的JCG合作伙伴 Hebert Coelho 對LazyInitializationException的四個解決方案 。
翻譯自: https://www.javacodegeeks.com/2012/07/four-solutions-to-lazyinitializationexc.html