日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

LazyInitializationException的四种解决方案–第1部分

發(fā)布時間:2023/12/3 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LazyInitializationException的四种解决方案–第1部分 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在今天的帖子中,我們將討論常見的LazyInitializationException錯誤。 我們將看到四種避免該錯誤的方法,以及每種方法的優(yōu)缺點。在本文的最后,我們將討論EclipseLink如何處理該異常。

為了看到LazyInitializationException錯誤并進行處理,我們將使用帶有EJB 3的應用程序JSF 2。

帖子主題:

  • 了解問題后,為什么會發(fā)生LazyInitializationException?
  • 通過注釋加載集合
  • 通過View中的Open Session加載收集(View中的事務)
  • 使用PersistenceContextType.EXTENDED的有狀態(tài)EJB加載收集
  • 通過聯(lián)接查詢加載集合
  • EclipseLink和惰性集合初始化

在本文的結尾,您將找到要下載的源代碼。

注意 :在本文中,我們將找到一個簡單的代碼,該代碼不適用設計模式。 本文的重點是展示LazyInitializationException的解決方案。

您將在這里找到的解決方案適用于Web技術,例如帶Struts的JSP,帶VRaptor的JSP,帶Servlet的JSP,帶其他功能的JSF。

模型類

在今天的帖子中,我們將使用“人與狗”類:

package com.model;import javax.persistence.*;@Entity public class Dog {@Id@GeneratedValue(strategy = GenerationType.AUTO)private int id;private String name;public Dog() {}public Dog(String name) {this.name = name;}//get and set }package com.model;import java.util.*;import javax.persistence.*;@Entity public class Person {@Id@GeneratedValue(strategy = GenerationType.AUTO)private int id;private String name;@OneToMany@JoinTable(name = 'person_has_lazy_dogs')private List<Dog> lazyDogs;public Person() {}public Person(String name) {this.name = name;}// get and set }

注意,通過這兩個類,我們將能夠創(chuàng)建LazyInitializationException。 我們有一個帶狗名單的人類。

我們還將使用一個類來處理數據庫操作(EJB DAO),并使用ManagedBean來幫助我們創(chuàng)建錯誤并進行處理:

package com.ejb;import java.util.List;import javax.ejb.*; import javax.persistence.*;import com.model.*;@Stateless public class SystemDAO {@PersistenceContext(unitName = 'LazyPU')private EntityManager entityManager;private void saveDogs(List<Dog> dogs) {for (Dog dog : dogs) {entityManager.persist(dog);}}public void savePerson(Person person) {saveDogs(person.getLazyDogs());saveDogs(person.getEagerDogs());entityManager.persist(person);}// you could use the entityManager.find() method alsopublic 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;} }package com.mb;import javax.ejb.EJB; import javax.faces.bean.*;import com.ejb.SystemDAO; import com.model.*;@ManagedBean @RequestScoped public class DataMB {@EJBprivate SystemDAO systemDAO;private Person person;public Person getPerson() {return systemDAO.findByName('Mark M.');} }

為什么會發(fā)生LazyInitializationException?

Person類具有一個Dog列表。 顯示人員數據的最簡單,最胖的方法是使用entityManager.find()方法并遍歷頁面(xhtml)中的集合。

我們想要的只是讓代碼波紋管做到這一點……

// you could use the entityManager.find() method alsopublic 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 Person getPerson() {return systemDAO.findByName('Mark M.');}<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN''http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'> <html xmlns='http://www.w3.org/1999/xhtml'xmlns:f='http://java.sun.com/jsf/core'xmlns:h='http://java.sun.com/jsf/html'xmlns:ui='http://java.sun.com/jsf/facelets'> <h:head></h:head> <h:body><h:form><h:dataTable var='dog' value='#{dataMB.personByQuery.lazyDogs}'><h:column><f:facet name='header'>Dog name</f:facet>#{dog.name}</h:column></h:dataTable></h:form> </h:body> </html>

注意,在上面的代碼中,我們要做的就是在數據庫中找到一個人并將其狗顯示給用戶。 如果您嘗試使用上面的代碼訪問該頁面,則會看到以下異常:

[javax.enterprise.resource.webcontainer.jsf.application] (http–127.0.0.1-8080-2) Error Rendering View[/getLazyException.xhtml]: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.model.Person.lazyDogs, no session or session was closed at org.hibernate.collection.internal.AbstractPersistentCollection. throwLazyInitializationException(AbstractPersistentCollection.java:393) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]at org.hibernate.collection.internal.AbstractPersistentCollection. throwLazyInitializationExceptionIfNotConnected (AbstractPersistentCollection.java:385) [ hibernate-core-4.0.1.Final.jar:4.0.1.Final]at org.hibernate.collection.internal.AbstractPersistentCollection. readSize(AbstractPersistentCollection.java:125) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]

為了更好地理解此錯誤,讓我們看看JPA / Hibernate如何處理這種關系。

每次我們在數據庫中進行查詢時,JPA都會帶入該類的所有信息。 這個規(guī)則的例外是當我們談論列表(集合)時。 我們擁有一個公告對象的圖像,其中包含70,000封將接收此公告的電子郵件列表。 如果您只想在屏幕上向用戶顯示公告名稱,請想象一下,如果將70,000封電子郵件加載了該名稱,JPA的工作就可以了。

JPA為類屬性創(chuàng)建了一種名為“延遲加載”的技術。 我們可以通過以下方式定義延遲加載:“僅在需要時才從數據庫加載所需的信息”。

注意,在上面的代碼中,數據庫查詢將返回一個Person對象。 當您訪問lazyDogs集合時,容器將注意到lazyDogs集合是一個lazy屬性,它將“詢問” JPA以從數據庫加載該集合。

在執(zhí)行查詢的那一刻( 將帶來lazyDogs集合 ),將發(fā)生異常。 當JPA / Hibernate嘗試訪問數據庫以獲取此惰性信息時,JPA將注意到沒有打開的集合。 這就是為什么發(fā)生異常(缺少打開的數據庫連接)的原因。

默認情況下,每個以@Many結尾的關系都會被延遲加載:@OneToMany和@ManyToMany。 默認情況下,將急切加載以@One結尾的每個關系:@ManyToOne和@OneToOne。 如果要設置延遲加載的基本字段(例如,字符串名稱),請執(zhí)行:@Basic(fetch = FetchType.LAZY)。

如果開發(fā)人員未將每個基本字段(例如,String,int,double)放在類中,我們將立即加載它們。

關于默認值的一個有趣主題是,對于同一批注,您可能會發(fā)現每個JPA實現(EclipseLink,Hibernate,OpenJPA)具有不同的行為。 我們將在稍后討論。

通過注釋加載集合

加載對象時,最簡單,最胖的方法是通過注釋添加惰性列表。 但這永遠不是最好的方法 。

在下面的代碼中,我們將介紹如何通過注釋熱切地加載集合:

@OneToMany(fetch = FetchType.EAGER) @JoinTable(name = 'person_has_eager_dogs') private List<Dog> eagerDogs;<h:dataTable var='dog' value='#{dataMB.person.eagerDogs}'><h:column><f:facet name='header'>Dog name</f:facet>#{dog.name}</h:column> </h:dataTable>

這種方法的優(yōu)點和缺點:

優(yōu)點

缺點

易于設置

如果該類具有多個集合,則這將不利于服務器性能

該列表將始終與加載的對象一起提供

如果只想顯示名稱或年齡之類的基本類屬性,則將所有配置為EAGER的集合加載名稱和年齡

如果EAGER集合只有幾個項目,則此方法將是一個很好的選擇。 如果此人只有2條,3條狗,則您的系統(tǒng)將能夠非常輕松地處理它。 如果稍后“ Persons狗”收集開始確實增長很多,那么這對服務器性能將不會有好處。

這種方法可以應用于JSE和JEE。

通過View中的Open Session加載收集(View中的事務)

在視圖中打開會話(或在視圖中打開事務)是一種設計模式,您將使數據庫連接保持打開狀態(tài),直到用戶請求結束。 當應用程序訪問一個惰性集合時,Hibernate / JPA會進行數據庫查詢而不會出現問題,不會引發(fā)任何異常。

當將此設計模式應用于Web應用程序時,將使用實現Filter的類,該類將接收所有用戶請求。 此設計模式非常容易應用,并且有兩個基本操作:打開數據庫連接和關閉數據庫連接。

您將需要編輯“ web.xml ”并添加過濾器配置。 在下面檢查我們的代碼如何:

<filter><filter-name>ConnectionFilter</filter-name><filter-class>com.filter.ConnectionFilter</filter-class></filter><filter-mapping><filter-name>ConnectionFilter</filter-name><url-pattern>/faces/*</url-pattern></filter-mapping>package com.filter;import java.io.IOException;import javax.annotation.Resource; import javax.servlet.*; import javax.transaction.UserTransaction;public class ConnectionFilter implements Filter {@Overridepublic void destroy() {}@Resourceprivate UserTransaction utx;@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {try {utx.begin();chain.doFilter(request, response);utx.commit();} catch (Exception e) {e.printStackTrace();}}@Overridepublic void init(FilterConfig arg0) throws ServletException {} }<h:dataTable var='dog' value='#{dataMB.person.lazyDogs}'><h:column><f:facet name='header'>Dog name</f:facet>#{dog.name}</h:column> </h:dataTable>

這種方法的優(yōu)點和缺點:

優(yōu)點

缺點

模型類別將不需要編輯

所有交易必須在過濾器類中處理

開發(fā)人員必須對數據庫事務錯誤非常謹慎。 可以通過ManagedBean / Servlet發(fā)送成功消息,但是當數據庫提交事務時,可能會發(fā)生錯誤。

可能會發(fā)生N + 1效應(如下所示)

這種方法的主要問題是N + 1效應。 當該方法將一個人返回到用戶頁面時,該頁面將迭代dogs集合。 當頁面訪問惰性集合時,將觸發(fā)新的數據庫查詢以顯示狗的惰性列表。 想象一下,如果狗有狗的集合,那么狗就是孩子。 為了加載狗子列表,將觸發(fā)其他數據庫查詢。 但是,如果孩子有其他孩子,那么JPA再次會觸發(fā)一個新的數據庫查詢……然后就可以了……

這是這種方法的主要問題。 一個查詢幾乎可以創(chuàng)建無限多個其他查詢。

這種方法可以應用于JSE和JEE。

繼續(xù)本教程的第二部分 。

參考: uaiHebert博客上的JCG合作伙伴 Hebert Coelho 對LazyInitializationException的四個解決方案 。


翻譯自: https://www.javacodegeeks.com/2012/07/four-solutions-to-lazyinitializationexc_05.html

總結

以上是生活随笔為你收集整理的LazyInitializationException的四种解决方案–第1部分的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。