Hibernate Lazy屬性與懶載入 整理

来源:http://www.cnblogs.com/unflynaomi/archive/2016/02/17/5194880.html
-Advertisement-
Play Games

lazy概念:要用到的時候,再去載入,對於關聯的集合來說,只有當訪問到的時候,才去載入它所關聯的集合,比如一個user對應很多許可權,只有當user.getRights()的時候,才發出select right的語句,在訪問到rights之前,rights是一個PersisitSet對於實體類來說,只


lazy概念:要用到的時候,再去載入,對於關聯的集合來說,只有當訪問到的時候,才去載入它所關聯的集合,比如一個user對應很多許可權,只有當user.getRights()的時候,才發出select right的語句,在訪問到rights之前,rights是一個PersisitSet對於實體類來說,只有當它的屬性被訪問到時,才會真正載入這個實體類,在它的屬性沒有被訪問到之前,這個實體類是一個代理對象。

1.在集合中定義:<set><list>標簽上

,可以取值:true/false/extra

<set name="name" lazy="true/false/extra" >
預設為true

預設為true情況下,當使用到了Set對象,才會把整個set全部查詢出來。

false情況下,不使用Lazy,查詢Lazy所屬的對象時,set就會被查詢上來。extra情況下,比較智能,根據查詢的內容,生成不同的SQL語句。效率會高一些。

例子:在我們前邊多對一的關係中(部門與員工):

Department.hbm.xml

[html] view plain copy

 print?

  1. <set name="emps" inverse="true" lazy="false">  
  2.             <key column="depart_id" />  
  3.             <one-to-many class="Employee" />  
  4.         </set>  

通過這個可以關閉預設的懶載入

2單端關聯 <one-to-one><many-to-one>單端關聯上,可以取值:false/proxy/no-proxy

<many-to-one name="name" lazy="false/proxy/no-proxy">
預設為proxy

false:不使用Lazy。此關聯總是被預先抓取

proxy:使用懶載入

no-proxy:指定此屬性應該在實例變數第一次被訪問時應該延遲抓取(fetche lazily

[html] view plain copy

 print?

  1. <many-to-one name="depart" column="depart_id" lazy="false"/>   

 

  • lazy="proxy" applies to single objects (ie foo.SingleBar)
  • lazy="true" applies to collections of objects (ie foo.MultiBar)

(You can't set lazy="proxy" to a collection, nor can you set lazy="true" to a single reference. Either will cause NH to throw a XmlSchemaException which is a little cryptic to beginners.)

 

 

比如說在college.hbm.xml裡面寫上

<set name="majors" inverse="true" lazy="false" cascade="delete">

載入學院時立刻載入學院的專業,那麼在查詢所有學院時,產生的sql語句如下:

Hibernate: select majors0_.college_id as college_2_3_0_, majors0_.major_id as major_id1_6_0_, majors0_.major_id as major_id1_6_1_, majors0_.college_id as college_2_6_1_, majors0_.major_name as major_na3_6_1_, majors0_.major_code as major_co4_6_1_ from studorm.tb_major majors0_ where majors0_.college_id=?

 

 

在查詢所有學院的時候,會立刻載入每個學院的專業,所以如非必要,不要加上

十分浪費資源

 

 

以下來自:http://www.cnblogs.com/wukenaihe/archive/2013/06/11/3131640.html

 

3.class標簽

除了用在<set>  <one-to-one><many-to-one>標簽上,lazy還能用在

* <class>標簽上,可以取值:true/false ,在hibernate3以上版本,預設是true
* <property>
標簽上,可以取值:true/false

 

在<class>標簽上,可以取值:true/false ,在hibernate3以上版本,預設是true

 

預設為true,可不寫,在執行查詢語句時不進行,比如session.load(id)時,不執行sql語句(session.get(id)不支持lazy),而是在具體獲取參數時,執行sql語句,比如obj.getName()。

 

<class>標簽上的lazy特性只對普通屬性起作用

 

<class>標簽上的lazy不會影響到單端關聯上的lazy特性

 

3.1 延遲載入策略(預設)

  如果想對實體對象使用延遲載入,必須要在實體的映射配置文件中進行相應的配置

  <class name="Person" table="PERSON" lazy="true">

1 tx = session.beginTransaction();

2 Person p=(Person) session.load(Person.class, "001");//(1)

3 System.out.println("0: "+p.getPersonId());//(2)

4 System.out.println("0: "+p.getName());//(3)

5 tx.commit();

6 session.close();

  執行到(1)並沒有出現sql語句,並沒有從資料庫中抓取數據。這個時候查看記憶體對象p如下:

2.1 person對象load時的記憶體快照

  觀察person對象,我們可發現是Person$$EnhancerBy..的類型的對象。這裡所返回的對象類型就是Person對象的代理對象,在hibernate中通過使用CGLB來先動態構造一個目標對象的代理類對象,並且在代理對象中包含目標對象的所有屬性和方法。所以,對於客戶端而言是否為代理類是無關緊要的,對他來說是透明的。這個對象中,僅僅設置了id屬性(即personId的值),這是為了便於後面根據這個Id從資料庫中來獲取數據。

   運行到(2)處,輸出為001,但是仍然沒有從資料庫裡面讀取數據。這個時候代理類的作用就體現出來了,客戶端覺得person類已經實現了(事實上並未創建)。但是,如果這個會後session關閉,再使用person對象就會出錯了。

   調試運行到(3)處,要用到name屬性,但是這個值在資料庫中。所以hibernate從資料庫裡面抓取了數據,sql語句如下所示:

Hibernate:

select

person0_.PERSONID as PERSONID3_0_,

person0_.NAME as NAME3_0_

from

PERSON person0_

where

person0_.PERSONID=?

  這時候,我們查看記憶體裡面的對象如下:

2.2 class延遲載入時記憶體對象

  真正的Person對象放在CGLIB$CALLBACK_0對象中的target屬性里。

  這樣,通過一個中間代理對象,Hibernate實現了實體的延遲載入,只有當用戶真正發起獲得實體對象屬性的動作時,才真正會發起資料庫查詢操作。所以實體的延遲載入是用通過中間代理類完成的,所以只有session.load()方法才會利用實體延遲載入,因為只有session.load()方法才會返回實體類的代理類對象。

3.2 非延遲載入策略

  Hibernate預設的策略便是非延遲載入的,所以設置lazy=false

    

1 tx = session.beginTransaction();

2 Person p=(Person) session.load(Person.class, "001");//(1)

3 System.out.println("0: "+p.getPersonId());//(2)

4 System.out.println("0: "+p.getName());//(3)

5 tx.commit();

6 session.close();

  調試運行到(1)處時,hibernate直接執行如下sql語句:

Hibernate:

select

person0_.PERSONID as PERSONID3_0_,

person0_.NAME as NAME3_0_

from

PERSON person0_

where

person0_.PERSONID=?

  我們在查看記憶體快照如下:

      這個時候就不是一個代理類了,而是Person對象本身了。裡面的屬性也已經全部普通屬性也全部被載入。這裡說普通屬性是因為addresses這個集合對象並沒有被載入,因為set自己本身也可以設置lazy屬性。所以,這裡也反映出class對象的lazy並不能控制關聯或集合的載入策略。

2.3 總結

  Hibernate<class lazy="">預設為true。如果,在load的時候只會返回一個代理類,並不會正在從資料庫中讀取數據。第一次用到時,會將所有普通屬性set這種就不是)全部載入進來。如果第一次使用到時,session已經關閉將發生錯誤。

  如果顯式是設置lazy=falseload的時候即會把所有普通屬性全部讀取進來。而且,返回的將是一個真正的該類型的對象(Person),而不是代理類。

4欄位載入(property)

  在Hibernate3中,引入了一種新的特性——屬性的延遲載入,這個機制又為獲取高性能查詢提供了有力的工具。在大數據對象讀取時,如Person對象中有一個School欄位,該欄位是一個java.sql.Clob類型,包含了用戶的簡歷信息,當我們載入該對象時,我們不得不每一次都要載入這個欄位,而不論我們是否真的需要它,而且這種大數據對象的讀取本身會帶來很大的性能開銷。

1  <class lazy="false">

  配置如下

1 tx = session.beginTransaction();

2 Person p=(Person) session.load(Person.class, "001");//(1)

3 System.out.println("");//(2)

4 System.out.println("0: "+p.getPersonId());//(3)

5 System.out.println("0: "+p.getName());//(4)

6 System.out.println("0: "+p.getSchool());//(5)

7 tx.commit();

1 <property name="name" type="java.lang.String">

2 <column name="NAME" />

3 </property>

4 <property name="school" type="java.lang.String" lazy="true">

5 <column name="SCHOOL"></column>

6 </property>

       當運行到1的時候,全部載入了,執行語句如下:

Hibernate:

select

person0_.PERSONID as PERSONID3_0_,

person0_.NAME as NAME3_0_,

person0_.SCHOOL as SCHOOL3_0_

from

PERSON person0_

where

person0_.PERSONID=?

  所有普通屬性都均已載入。

2<class lazy="true">

  Schoollazy屬性自然還是true。當程式運行到(4)時,也同樣載入了全部屬性,執行瞭如下sql

Hibernate:

select

person0_.PERSONID as PERSONID3_0_,

person0_.NAME as NAME3_0_,

person0_.SCHOOL as SCHOOL3_0_

from

PERSON person0_

where

person0_.PERSONID=?

  結果就是無效,不管採用何種策略都是無效的,和我們想想的有較大出路。下麵是一段來自hibernate官方文檔的話。

  Lazy property loading requires buildtime bytecode instrumentation. If your persistent classes are not enhanced, Hibernate will ignore lazy property settings and return to immediate fetching.

  應該是因為,我們並未用到編譯時位元組碼增強技術的原因。如果只對部分property進行延遲載入的話,hibernate還提供了另外的方式,也是更為推薦的方式,即HQL或者條件查詢。

  A different way of avoiding unnecessary column reads, at least for read-only transactions, is to use the projection features of HQL or Criteria queries. This avoids the need for buildtime bytecode processing and is certainly a preferred solution.

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 安裝環境: CentOS release 6.3 (Final) about 64bit cpu 1, http://www.oracle.com下載最新版的javase的jdk環境 比如我下載的是:jdk-8u73-linux-x64.tar.gz 2,上傳到 /usr/java下 3,tar -
  • public static void main(String[] args) { Integer i1 = new Integer(1); Integer i2 = new Integer(1); // i1,i2分別位於堆中不同的記憶體空間 System.out.println("i1 == i2:
  • 引用計數 Python預設的垃圾收集機制是“引用計數”,每個對象維護了一個ob_ref欄位。它的優點是機制簡單,當新的引用指向該對象時,引用計數加1,當一個對象的引用被銷毀時減1,一旦對象的引用計數為0,該對象立即被回收,所占用的記憶體將被釋放。它的缺點是需要額外的空間維護引用計數,不過最主要的問題是
  • session原理,session如何存儲,如何使用redis/分散式文件系統/資料庫存儲session,負載均衡中如何解決session不一致問題
  • 註:本文主要記錄自《深入分析java web技術內幕》"第四章 javac編譯原理" 1、javac作用 將*.java源代碼文件轉化為*.class文件 2、編譯流程 流程: 詞法分析器:將源碼轉換為Token流 將源代碼劃分成一個個Token(Token包含的元素類型看3.2) 語法分析器:將T
  • IO是輸入和輸出的簡稱,在實際的使用時,輸入和輸出是有方向的。就像現實中兩個人之間借錢一樣,例如A借錢給B,相對於A來說是借出,而相對於B來說則是借入。所以在程式中提到輸入和輸出時,也需要區分清楚是相對的內容。 在 程式中,輸入和輸出都是相對於當前程式而言的,例如從硬碟上讀取一個配置文件的內容到程式
  • 一、SSH框架的概念 SSH框架是java web開發流行的一個開源集合框架,SSH框架包含了Struts框架,Spring框架和Hibernate框架。SSH框架可以用於構建靈活、易於擴展的多層Web應用程式。 二、SSH框架的工作原理 SSH框架中的Struts負責攔截用戶請求,正常情況下用戶請
  • 1、路由是程式的方法和URL的一一映射。 在配置文件里,把經常訪問的路由放在前面,可以提高路由匹配的效率。 2、路由匹配的兩種方式 Annotation 允許在方法的上面用註釋定義方法運行狀態的功能 class UserController extends Controller{ /** * @Ro
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...