LazyInitializationException的四種解決方案–第1部分

在今天的帖子中,我們將討論常見的LazyInitializationException錯誤。 我們將看到四種避免該錯誤的方法,以及每種方法的優缺點。在本文的最后,我們將討論EclipseLink如何處理該異常。

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

帖子主題:

  • 了解問題后,為什么會發生LazyInitializationException?
  • 通過注釋加載集合
  • 通過View中的Open Session加載收集(View中的事務)
  • 使用PersistenceContextType.EXTENDED的有狀態EJB加載收集
  • 通過聯接查詢加載集合
  • 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
}

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

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

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.');}
}

為什么會發生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都會帶入該類的所有信息。 這個規則的例外是當我們談論列表(集合)時。 我們擁有一個公告對象的圖像,其中包含70,000封將接收此公告的電子郵件列表。 如果您只想在屏幕上向用戶顯示公告名稱,請想象一下,如果將70,000封電子郵件加載了該名稱,JPA的工作就可以了。

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

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

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

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

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

關于默認值的一個有趣主題是,對于同一批注,您可能會發現每個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>

這種方法的優點和缺點:

優點

缺點

易于設置

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

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

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

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

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

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

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

當將此設計模式應用于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>

這種方法的優點和缺點:

優點

缺點

模型類別將不需要編輯

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

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

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

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

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

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

繼續本教程的第二部分 。

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


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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/371720.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371720.shtml
英文地址,請注明出處:http://en.pswp.cn/news/371720.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

linux驅動

jeffies hz xtime 每秒鐘系統時鐘節拍數 prco < 內核內存視窗 include/linux/list.h < 內核的數據結構&#xff0c;鏈表 workques_struct 工作隊列轉載于:https://www.cnblogs.com/asreg/p/7148606.html

java 條碼識別_條碼識別示例代碼

package api.jisuapi.barcode;import api.util.HttpUtil;import net.sf.json.JSONArray;import net.sf.json.JSONObject;public class Read {public static final String APPKEY "your_appkey_here";// 你的appkeypublic static final String URL "https://ap…

終極JPA查詢和技巧列表–第2部分

這一部分是該系列文章的第一部分 。 JPA&#xff1a;NamedQuery&#xff0c;使用日期查詢&#xff0c;有關getSingleResult方法的警告 為了避免重復查詢代碼&#xff0c;提高性能并簡化維護查詢&#xff0c;我們可以使用NamedQueries。 NamedQuery使用JPQL作為語法&#xff0c…

設置UITableView設置contentsize

由于UITableView是繼承自UIScrollView的&#xff0c;所以他是可以設置contentsize的。 但是&#xff0c;我在試驗的過程中&#xff0c;初始化UITableView實例后&#xff0c;直接設置它的contentsize是不起作用&#xff0c;在搜尋相關資料得知&#xff0c;UITableView會自動設置…

java 線程什么時候結束_java線程什么時候讓出cpu?

Thread.sleep();sleep就是正在執行的線程主動讓出cpu&#xff0c;cpu去執行其他線程&#xff0c;在sleep指定的時間過后&#xff0c;cpu才會回到這個線程上繼續往下執行&#xff0c;如果當前線程進入了同步鎖&#xff0c;sleep方法并不會釋放鎖&#xff0c;即使當前線程使用sle…

Hibernate配置方式

Hibernate配置方式 Hibernate給人的感受是靈活的&#xff0c;要達到同一個目的&#xff0c;我們可以使用幾種不同的辦法。就拿Hibernate配置來說&#xff0c;常用的有如下三種方式&#xff0c;任選其一。 在 hibernate.cfg.xml 中加入元素 <property>、<mapping>&a…

js中 javascript:void(0) 用法詳解

javascript:void(0)表示不做任何動作。如&#xff1a; 復制代碼代碼如下:<a href"javascript:void(0);" οnclick"alert(ok);"></a> 這里表示這個鏈接不做跳轉動作&#xff0c;執行onClick事件。 我想使用過ajax的都常見這樣的代碼&#xff1…

帶有ActiveMQ的JMS

帶有ActiveMQ的JMS JMS是Java Message Service的縮寫&#xff0c;它提供了一種以松散耦合&#xff0c;靈活的方式集成應用程序的機制。 JMS以存儲和轉發的方式跨應用程序異步傳遞數據。 應用程序通過充當中介的MOM&#xff08;面向消息的中間件&#xff09;進行通信&#xff0c…

矩陣分解 java_使用矩陣分解為推薦系統

矩陣分解假設“潛在因素”&#xff0c;例如對用戶的意大利食物的偏好和項目食物的意外性與矩陣中的評級有關 .因此&#xff0c;整個問題類型轉變為矩陣重構問題&#xff0c;存在許多不同的解決方案 . 一個簡單的&#xff0c;可能很慢的解決方案是(除了ALS和其他一些矩陣重建的可…

用戶故事排球教練助手

計劃&#xff1a;估計這個任務需要一周時間 需求分析&#xff1a;作為一名排球教練助手&#xff0c;我需要了解每場每位隊員的技術動作&#xff0c;每場比賽每位隊員的得分情況&#xff0c;以便教練更好的了解到每位隊員的發揮情況和特長。 設計文檔&#xff1a;用戶進入此界面…

TMS320DM642學習----第一篇(硬件連接)

DSP設備型號&#xff1a;SEED-DTK-VPM642&#xff08;目前實驗室用途&#xff1a;視頻處理&#xff0c;圖像處理方向&#xff0c;預計搭載目標跟蹤以及云臺防抖等算法&#xff09; 官網鏈接&#xff1a;http://www.seeddsp.com/index.php/Home/Product/detail/name/1/id/174.ht…

字符串內存內部

本文基于我對StackOverflow的回答 。 我正在嘗試解釋String類如何存儲文本&#xff0c;內部存儲和常量池如何工作。 這里要理解的要點是String Java對象與其內容– private value字段下的char[]之間的區別。 String基本上是char[]數組的包裝器&#xff0c;將其封裝并使其無法修…

關于inline-block 元素之間為何會產生間隔

關于inline-block 元素之間為何會產生間隔 現象&#xff1a; <body><input type"text"><input type"text"> </body> 在瀏覽器中的表現&#xff1a; 實時上不僅僅是 inline-block 會導致這種現象。 inline 也會導致。 那問題來了&a…

java 入參 是 枚舉_java 枚舉 參數傳遞

展開全部這樣做是不行的&#xff0c;原因是&#xff1a;Java中的對象實例化都是在堆中&#xff0c;如果是普通的類實例變量&#xff0c;比如在方法636f707962616964757a686964616f313333376166371中定義的普通類實例變量&#xff0c;傳到了方法2中&#xff0c;由于方法1和方法2…

loadView的使用總結

一、loadView 1. loadView什么時候被調用&#xff1f; 每次訪問UIViewController的view&#xff08;如 controller.view、self.view&#xff09;并且view為nil&#xff0c;loadView方法就會被調用 2. 有什么作用 loadView 方法是用來負責創建UIViewController的view 3. 默認實…

數據庫備份 java jar_Java實現數據庫備份并利用ant導入SQL腳本

?數據備份對于經常在運維部署方面的工作者來說&#xff0c;是一件相對簡單的事情&#xff0c;都可以通過某一個SQL工具進行備份&#xff0c;但是如果在項目運行當中&#xff0c;我們需要對數據進行實時&#xff0c;或者是每隔一星期&#xff0c;一個月&#xff0c;等等進行數據…

JSF簡單Ajax示例

今天&#xff0c;我們將看到一些使用JSF的Ajax簡單樣本。 如果要查看有關JSF / Web應用程序的其他文章&#xff0c;請單擊以下鏈接&#xff1a; 重定向后的JSF持久化對象和消息 &#xff0c; 使用JAAS和JSF進行用戶登錄驗證 &#xff0c; JSF&#xff1a;Converter and Bean Au…

常用的好用的window工具

1. FastStone Capture截圖錄屏軟件 百度軟件中心&#xff1a;http://rj.baidu.com/soft/detail/13504.html?ald 注冊企業版&#xff1a; 用戶名&#xff1a;c1ikm 注冊碼&#xff1a;AXMQX-RMMMJ-DBHHF-WIHTV 中文輸入亂碼解決方法&#xff1a; 2. Notepad文本編輯器&#xff…

表分區

http://www.cnblogs.com/leestar54/p/6225821.html轉載于:https://www.cnblogs.com/jouny/p/6262850.html

java飛鴿傳書_feige 飛鴿傳書源代碼java 實現不錯的聯系網絡編程的資料飛鴿傳書的GUI(java實現) - 下載 - 搜珍網...

我的飛鴿傳書/FileFilter.java我的飛鴿傳書/FileNameExtensionFilter.java我的飛鴿傳書/飛鴿傳書/classes/feige/About.class我的飛鴿傳書/飛鴿傳書/classes/feige/ConnectOthers$ReadMessageThread.class我的飛鴿傳書/飛鴿傳書/classes/feige/ConnectOthers.class我的飛鴿傳書…