1. 程式人生 > >hibernate 使用延遲載入產生的問題以及對應的解決方法

hibernate 使用延遲載入產生的問題以及對應的解決方法

Hibernate延時載入,其實這個異常寫的非常之清楚,就是會話關閉,無法對Hibernate實體進行操作。造成這樣的情況有很多,什麼書寫錯誤啊,邏輯錯誤啊。

但就此說一下關於lazy機制:

Hibernate延時載入包括延遲初始化錯誤,這是運用Hibernate開發專案時最常見的錯誤。如果對一個類或者集合配置了延遲檢索策略,那麼必須當代理類例項或代理集合處於持久化狀態(即處於Session範圍內)時,才能初始化它。如果在遊離狀態時才初始化它,就會產生延遲初始化錯誤。

下面把Customer.hbm.xml檔案的< class>元素的lazy屬性設為true,表示使用延遲檢索策略:

  1. <classname="mypack.Customer"table="CUSTOMERS"lazy="true">

當執行Session的load()方法時,Hibernate不會立即執行查詢CUSTOMERS表的select語句,僅僅返回Customer類的代理類的例項,這個代理類具由以下特徵:

(1) 由Hibernate在執行時動態生成,它擴充套件了Customer類,因此它繼承了Customer類的所有屬性和方法,但它的實現對於應用程式是透明的。

(2) 當Hibernate建立Customer代理類例項時,僅僅初始化了它的OID屬性,其他屬性都為null,因此這個代理類例項佔用的記憶體很少。

(3)當應用程式第一次訪問Customer代理類例項時(例如呼叫customer.getXXX()或customer.setXXX ()方法), Hibernate會初始化代理類例項,在初始化過程中執行select語句,真正從資料庫中載入Customer物件的所有資料。但有個例外,那就是當 應用程式訪問Customer代理類例項的getId()方法時,Hibernate不會初始化代理類例項,因為在建立代理類例項時OID就存在了,不必 到資料庫中去查詢。

提示:Hibernate採用CGLIB工具來生成持久化類的代理類。CGLIB是一個功能強大的Java位元組碼生成工具,它能夠在程式執行時動態生成擴 展 Java類或者實現Java介面的代理類。

以下程式碼先通過Session的load()方法載入Customer物件,然後訪問它的name屬性:

  1. tx = session.beginTransaction();   
  2. Customer customer=(Customer)session.load(Customer.class,new Long(1));   
  3. customer.getName();   
  4. tx.commit();  

在執行session.load ()方 法時Hibernate不執行任何select語句,僅僅返回Customer類的代理類的例項,它的OID為1,這是由load()方法的第二個 引數指定的。當應用程式呼叫customer.getName()方法時,Hibernate會初始化Customer代理類例項,從資料庫中載入 Customer物件的資料,執行以下select語句:

  1. select * from CUSTOMERS where ID=1;   
  2. select * from ORDERS where CUSTOMER_ID=1;  

當< class>元素的lazy屬性為true,會影響Session的load()方法的各種執行時行為,下面舉例說明。

1.如果載入的Customer物件在資料庫中不存在,Session的load()方法不會丟擲異常,只有當執行customer.getName()方法時才會丟擲以下異常:

  1. ERROR LazyInitializer:63 - Exception initializing proxy   
  2. net.sf.hibernate.ObjectNotFoundException: No row with the given identifier exists: 1, of class:   
  3. mypack.Customer  

2.如果在整個Session範圍內,應用程式沒有訪問過Customer物件,那麼Customer代理類的例項一直不會被初始化,Hibernate不會執行任何select語句。以下程式碼試圖在關閉Session後訪問Customer遊離物件:

  1. tx = session.beginTransaction();   
  2. Customer customer=(Customer)session.load(Customer.class,new Long(1));   
  3. tx.commit();   
  4. session.close();   
  5. customer.getName();  

由於引用變數customer引用的Customer代理類的例項在Session範圍內始終沒有被初始化,因此在執行customer.getName()方法時,Hibernate會丟擲以下異常(Hibernate延時載入的問題之一):

  1. ERROR LazyInitializer:63 - Exception initializing proxy   
  2. net.sf.hibernate.HibernateException: Couldnotinitializeproxy-theowningSessionwasclosed  

由此可見,Customer代理類的例項只有在當前Session範圍內才能被初始化。

3.net.sf.hibernate.Hibernate類的initialize()靜態方法用於在Session範圍內顯式初始化代理類例項,isInitialized()方法用於判斷代理類例項是否已經被初始化。例如:

  1. tx = session.beginTransaction();   
  2. Customer customer=(Customer)session.load(Customer.class,new Long(1));   
  3. if(!Hibernate.isInitialized(customer))   
  4. Hibernate.initialize(customer);   
  5. tx.commit();   
  6. session.close();   
  7. customer.getName();  

以上程式碼在Session範圍內通過Hibernate類的initialize()方法顯式初始化了Customer代理類例項,因此當Session關閉後,可以正常訪問Customer遊離物件。

4.當應用程式訪問代理類例項的getId()方法時,不會觸發Hibernate初始化代理類例項的行為,例如:

  1. tx = session.beginTransaction();   
  2. Customer customer=(Customer)session.load(Customer.class,new Long(1));   
  3. customer.getId();   
  4. tx.commit();   
  5. session.close();   
  6. customer.getName();  

當應用程式訪問customer.getId()方法時,該方法直接返回Customer代理類例項的OID值,無需查詢資料庫。由於引用變數 customer始終引用的是沒有被初始化的Customer代理類例項,因此當Session關閉後再執行customer.getName()方法, Hibernate會丟擲以下異常(Hibernate延時載入的問題之一):

  1. ERROR LazyInitializer:63 - Exception initializing proxy   
  2. net.sf.hibernate.HibernateException: Couldnotinitializeproxy-theowningSessionwasclosed  

解決方法:

由於hibernate採用了lazy=true,這樣當你用hibernate查詢時,返回實際為利用cglib增強的代理類,但其並沒有實際填 充;當你在前端,利用它來取值(getXXX)時,這時Hibernate才會到資料庫執行查詢,並填充物件,但此時如果和這個代理類相關的session已關閉掉,就會產生種錯誤.

在做一對多時,有時會出現"could not initialize proxy - clothe owning Session was sed,這個好像是hibernate的快取問題.問題解決:需要在< many-to-one>裡設定lazy="false". 但有可能會引發另一個異常叫

  1. failed to lazily initialize a collection of role: XXXXXXXX, no session or session was closed  

解決方法:在web.xml中加入 

  1. <filter>
  2. <filter-name>hibernateFilter< /filter-name>
  3. <filter-class>
  4.      org.springframework.orm.hibernate3.support.OpenSessionInViewFilter   
  5. < /filter-class>
  6. < /filter>   
  7. <filter-mapping>
  8. <filter-name>hibernateFilter< /filter-name>
  9. <url-pattern>*.do< /url-pattern>
  10. < /filter-mapping>

就可以了。

相關推薦

hibernate 使用延遲載入產生的問題以及對應解決方法

Hibernate延時載入,其實這個異常寫的非常之清楚,就是會話關閉,無法對Hibernate實體進行操作。造成這樣的情況有很多,什麼書寫錯誤啊,邏輯錯誤啊。 但就此說一下關於lazy機制: Hibernate延時載入包括延遲初始化錯誤,這是運用Hibernate開發專

hibernate 延遲載入 load和get方法

延遲載入 延遲載入: 當hibernate從資料庫中載入某個物件時,不載入關聯的物件,而只是生成了代理物件。使用session中的load的方法(在沒有改變lazy屬性,屬性值為true的情況下)獲取到的也是代理物件。 立即載入: 當Hibernat

hibernate延遲載入以及no-session

延遲載入:延遲載入(lazy load懶載入)是當在真正需要資料時,才執行SQL語句進行查詢,避免了無謂的效能開銷。  延遲載入分類:  01.類級別的查詢策略  02.一對多和多對多關聯的查詢策略  03.多對一關聯的查詢策略 類級別的查詢策略      1.類級別

Chrome瀏覽器點擊 input file上傳按鈕時延遲3-5秒的解決方法

chrome瀏覽器 input file1. Google chrome 瀏覽器在52版本之後出現一個bug,就是點擊 input file上傳按鈕時反應很慢,需要等待3-5秒種之後才能彈出選擇文件的對話框。比如windows裏可能是這樣:MAC裏可能是這樣:Chrome瀏覽器點擊 input file上傳

Android 8.0 的部分坑及對應解決方法

channel 資料 兼容 androi adb install 只需要 方法 tps 雖然 Android 9.0 都已經面世了,本篇文章寫的有點遲了。 但是遲到好過不到,因此基於此這邊還是記錄一下項目中遇到的 Android 8.0 的坑及對應解決方法。 每次系統

Hibernate延遲載入(查詢優化),關聯級別延遲載入優化策略

1. 類級別延遲載入: 類級別使用延時載入,可以在class標籤上修改是否使用延遲載入 <class name="com.ssh.domain.Customer" table="cst_customer"> 2 關聯級別延遲載入:預設使用到的時候才進行查詢()

ConcurrentModificationException: 集合異常——產生原因和解決方法

:注意事項:迭代器在使用的時候,有人為了方便,如下使用就會有問題 System.out.println(((Student)it.next()).getName()+”---”+((Student)it.next()).getAge()); 注意事項:迭代器在使用的時候,有人為了方便,如下使

QML使用webkit載入網頁報錯解決方法 qml: Error creating SSL context ()

折騰了三天!!!!! QT簡直是太坑爹了!!!!!! QML載入網頁,用webkit,webview總是載入不出來網頁!!!!!! 最後列印了錯誤,發現是SSL不對,看網上好多人說要重新安裝OPENSSL,好複雜好複雜,最後發現就是QT執行時候缺少了兩個dll!!!!!!!!!!!!!!

hibernate延遲載入和session關閉問題

1.關閉延遲載入特性 2.在session關閉之前先獲取需要查詢的資料,可以使用工具方法Hibernate.isInitialized()判斷物件是否被載入,如果沒有被載入則可以使用Hibernate.initialize()方法載入物件。 使用攔截器或過濾器延長Session的生命週期直到

vue頁面載入閃爍問題的解決方法

v-if 和 v-show 的區別 v-if只會在滿足條件時才會編譯,而v-show不管是否滿足條件始終會編譯,v-show的顯示與隱藏只是簡單的切換CSS的display屬性。 也就是說,在使用v-if時,若值為false,那麼頁面將不會有這個html標籤生成。而v-show:不論其值是false還是t

hibernate延遲載入(get和load的區別)

在hibernate中我們知道如果要從資料庫中得到一個物件,通常有兩種方式,一種是通過session.get()方法,另一種就是通過session.load()方法,然後其實這兩種方法在獲得一個實體物件時是有區別的,在查詢效能上兩者是不同的。 一.load載入方式 當使用

Spring Boot下 org.hibernate.AnnotationException異常的一種解決方法

異常如下 Caused by: org.hibernate.AnnotationException: @OneToOne or @ManyToOne on com.xiaomo.xxxx.model.yyy.Clock.user references an un

org.hibernate.SessionException: Session is closed! 異常解決方法

    今天寫了一個SpringMVC的小應用,功能很簡單,在使用者登入的時候如果發現自己沒有使用者名稱和密碼就點選註冊,跳轉到註冊頁面註冊一個,如果註冊成功,自動跳轉到登入頁面,否則跳到錯誤頁面。     問題出現在註冊成功後登入的時候。如果直接登入不存在這個問題。問題的

JAVA以UTF-8編碼格式匯出CSV檔案,用office開啟產生亂碼的解決方法

一般java匯出為csv檔案程式碼如下 OutputStreamWriter osw = new OutputStreamWriter(resp.getOutputStream

7.Hibernate 延遲載入&立即載入

延遲載入的好處 1.降低了記憶體的開銷,在用到某些資料的時候才會到資料中進行查詢。 2.提高了程式執行效能。 注:如果session被關閉了,而你又想用到某些資料,這個時候使用延遲載入會出錯;需要立即

AJAX跨域產生原因及解決方法

什麼是跨域:        跨域問題來源於JavaScript的同源策略,即只有 協議+主機名+埠號 (如存在)相同,則允許相互訪問。也就是說JavaScript只能訪問和操作自己域下的資源,不能訪問和操作其他域下的資源。跨域問題是針對JS和ajax的,html本身沒有跨域問

系統跟新後,VS2012不能新建專案,也不能載入專案問題的解決方法

【問題】 【1】VS2012不能夠新建專案,也不能載入專案 【2】出現不能夠正確在家Visual C++ Package 【解決方法】 到微軟官網下載VS2012更新 KB2781514,大

Hibernate延遲載入問題

  Hibernate延遲載入是專案中非常常用的技術。通過使用Hibernate延遲載入機制可以在載入資料是不必載入全部資料,而是隻載入我們需要的那部分,其餘部分在需要使用時才從資料庫裝載,以此來減少資

vue載入顯示{{xxx}}的解決方法

一般vue.js檔案放在最後,由於瀏覽器是從頭到尾的渲染機制,在沒有讀取到識別符對應的js控制語句就會直接顯示{{xxx}} 這個問題可以用vue的一個特點解決,就是Vue會自動遮蔽掉自定義屬性 我們可以為對應的dom節點新增一個自定義屬性,比如 dom-hidden(官

Linux的殭屍程序產生原因及解決方法

來源:http://www.blogdaren.com/post-882.html 1. 產生原因:     在UNIX 系統中,一個程序結束了,但是他的父程序沒有等待(呼叫wait / waitpid)他,那麼他將變成一個殭屍程序。通過ps命令檢視其帶有defunc