一、實體對象的延遲加載
如果想對實體對象使用延遲加載,必須要在實體的映射配置文件中進行相應的配置,如下所示:
<hibernate-mapping>
<class name="com.xsoft.entity.User" table="user" lazy="true">
……
</class>
</hibernate-mapping>
通過將class的lazy屬性設置爲true,來開啓實體的延遲加載特性。如果我們運行下面的代碼:
User user=(User)session.load(User.class,"1");(1)
System.out.println(user.getName());(2)
當運行到(1)處時,Hibernate並沒有發起對數據的查詢,如果我們此時通過一些調試工具(比如Eclipse的Debug工具),觀察此時 user對象的內存快照,我們會驚奇的發現,此時返回的可能是User$EnhancerByCGLIB$$bede8986類型的對象,而且其屬性爲 null,這是怎麼回事?session.load()方法會返回實體對象的代理類對象,這裏所返回的對象類型就是User對象的代理類對象。在 Hibernate中通過使用CGLIB,來實現動態構造一個目標對象的代理類對象,並且在代理類對象中包含目標對象的所有屬性和方法,而且所有屬性均被賦值爲null。通過調試器顯示的內存快照,我們可以看出此時真正的User對象,是包含在代理對象的CGLIB$CALBACK_0.target屬性中,當代碼運行到(2)處時,此時調用user.getName()方法,這時通過CGLIB賦予的回調機制,實際上調用 CGLIB$CALBACK_0.getName()方法,當調用該方法時,Hibernate會首先檢查CGLIB$CALBACK_0.target 屬性是否爲null,如果不爲空,則調用目標對象的getName方法,如果爲空,則會發起數據庫查詢,生成類似這樣的SQL語句:select * from user where id=’1’;來查詢數據,並構造目標對象,並且將它賦值到CGLIB$CALBACK_0.target屬性中。
這樣,通過一箇中間代理對象,Hibernate實現了實體的延遲加載,只有當用戶真正發起獲得實體對象屬性的動作時,才真正會發起數據庫查詢操作。所以實體的延遲加載是用通過中間代理類完成的,所以只有 session.load()方法纔會利用實體延遲加載,因爲只有session.load()方法纔會返回實體類的代理類對象。
二、集合類型的延遲加載
Hibernate的延遲加載機制針對集合類型的應用意義是最重大的,因爲這有可能使性能得到大幅度的提高。爲此Hibernate進行了大量的努力,其中包括對JDK Collection的進行了重新實現。我們在一對多關聯中定義的用來容納關聯對象的Set集合,並不是java.util.Set類型或其子類型,而是 net.sf.hibernate.collection.Set類型,通過使用自定義集合類的實現,Hibernate實現了集合類型的延遲加載。爲了對集合類型使用延遲加載,我們必須如下配置我們的實體類的關於關聯的部分:
<hibernate-mapping>
<class name="com.neusoft.entity.User" table="user">
…..
<set name="addresses" table="address" lazy="true" inverse="true">
<key column="user_id"/>
<one-to-many class="com.neusoft.entity.Arrderss"/>
</set>
</class>
</hibernate-mapping>
通過將<set>元素的lazy屬性設置爲true來開啓集合類型的延遲加載特性。我們看下面的代碼:
User user=(User)session.load(User.class,"1");
Collection addset=user.getAddresses(); (1)
Iterator it=addset.iterator(); (2)
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
}
當程序執行到(1)處時,這時並不會發起對關聯數據的查詢來加載關聯數據,只有運行到(2)處時,真正的數據讀取操作纔會開始,這時Hibernate會根據緩存中符合條件的數據索引,來查找符合條件的實體對象。
這裏我們引入了一個全新的概念——數據索引,下面我們首先將接一下什麼是數據索引。在Hibernate中對集合類型進行緩存時,是分兩部分進行緩存的,首先緩存集合中所有實體的id列表,然後緩存實體對象,這些實體對象的id列表,就是所謂的數據索引。當查找數據索引時,如果沒有找到對應的數據索引,這時就會一條select SQL的執行,獲得符合條件的數據,並構造實體對象集合和數據索引,然後返回實體對象的集合,並且將實體對象和數據索引納入Hibernate的緩存之中。另一方面,如果找到對應的數據索引,則從數據索引中取出id列表,然後根據id在緩存中查找對應的實體,如果找到就從緩存中返回,如果沒有找到,在發起select SQL查詢。在這裏我們看出了另外一個問題,這個問題可能會對性能產生影響,這就是集合類型的緩存策略。如果我們如下配置集合類型:
<hibernate-mapping>
<class name="com.neusoft.entity.User" table="user">
…..
<set name="addresses" table="address" lazy="true" inverse="true">
<cache usage="read-only"/>
<key column="user_id"/>
<one-to-many class="com.neusoft.entity.Arrderss"/>
</set>
</class>
</hibernate-mapping>
這裏我們應用了<cache usage="read-only"/>配置,如果採用這種策略來配置集合類型,Hibernate將只會對數據索引進行緩存,而不會對集合中的實體對象進行緩存。如上配置我們運行下面的代碼:
User user=(User)session.load(User.class,"1");
Collection addset=user.getAddresses();
Iterator it=addset.iterator();
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
}
System.out.println(“Second query……");
User user2=(User)session.load(User.class,"1");
Collection it2=user2.getAddresses();
while(it2.hasNext()){
Address address2=(Address)it2.next();
System.out.println(address2.getAddress());
}
運行這段代碼,會得到類似下面的輸出:
Select * from user where id=’1’;
Select * from address where user_id=’1’;
Tianjin
Dalian
Second query……
Select * from address where id=’1’;
Select * from address where id=’2’;
Tianjin
Dalian
我們看到,當第二次執行查詢時,執行了兩條對address表的查詢操作,爲什麼會這樣?這是因爲當第一次加載實體後,根據集合類型緩存策略的配置,只對集合數據索引進行了緩存,而並沒有對集合中的實體對象進行緩存,所以在第二次再次加載實體時,Hibernate找到了對應實體的數據索引,但是根據數據索引,卻無法在緩存中找到對應的實體,所以Hibernate根據找到的數據索引發起了兩條select SQL的查詢操作,這裏造成了對性能的浪費,怎樣才能避免這種情況呢?我們必須對集合類型中的實體也指定緩存策略,所以我們要如下對集合類型進行配置:
<hibernate-mapping>
<class name="com.neusoft.entity.User" table="user">
…..
<set name="addresses" table="address" lazy="true" inverse="true">
<cache usage="read-write"/>
<key column="user_id"/>
<one-to-many class="com.neusoft.entity.Arrderss"/>
</set>
</class>
</hibernate-mapping>
此時Hibernate會對集合類型中的實體也進行緩存,如果根據這個配置再次運行上面的代碼,將會得到類似如下的輸出:
Select * from user where id=’1’;
Select * from address where user_id=’1’;
Tianjin
Dalian
Second query……
Tianjin
Dalian
這時將不會再有根據數據索引進行查詢的SQL語句,因爲此時可以直接從緩存中獲得集合類型中存放的實體對象。
Hibernate延時加載
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
JPA 、 Hibernate 註解
yangyangisse
2018-08-27 20:03:00
Hibernate的關聯映射
entomb
2018-08-27 20:02:04
Hibernate數據加載方式
iteye_11720
2018-08-27 18:56:15
Hibernate持久化對象的狀態
明眸若雪
2018-08-27 18:48:13
Hibernate註解方式單表操作
shenshuibomb
2018-08-27 18:07:30
Hibernate單表操作
shenshuibomb
2018-08-27 18:06:51
hibernate註解方式實現一對多映射
shenshuibomb
2018-08-27 18:06:51
Hibernate一對多映射
shenshuibomb
2018-08-27 18:06:50
A simple Hibernate sample
shenshuibomb
2018-08-27 18:06:50
Hibernate中get和load的一點點區別。
shenshuibomb
2018-08-27 18:06:49
在Hibernate中配置一對多連接表
a157775541
2018-08-27 18:03:52
在Hibernate中配置多對多連接表
a157775541
2018-08-27 18:03:50
Hibernate 映射關係 ---One2Many單向關聯
qq_28059559
2018-08-27 17:53:33
Hibernate 映射關係 ---Many2Many 單向關聯
qq_28059559
2018-08-27 17:53:33
Hibernate 映射關係 ---One2Many 雙向關聯
qq_28059559
2018-08-27 17:53:22
24小時熱門文章
-
使用c#強大的表達式樹實現對象的深克隆之解決循環引用的問題
-
GPT-4o 引領人機交互新風向,向量數據庫賽道沸騰了
-
free AI online tools All In One
-
痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU啓動那些事(12.A)- uSDHC eMMC啓動時間(RT1170)
-
基於Ubuntu-22.04安裝K8s-v1.28.2實驗(二)使用kube-vip實現集羣VIP訪問
-
基於Ubuntu-22.04安裝K8s-v1.28.2實驗(三)數據卷掛載NFS(網絡文件系統)
-
企業大模型如何成爲自己數據的“百科全書”?
-
本地SSL證書過期 輸入命令在IIS自動生成
-
.NET週刊【5月第2期 2024-05-12】
-
基於Ubuntu-22.04安裝K8s-v1.28.2實驗(一)部署K8s