Hibernate深入學習(四):類級別的檢索策略
hibernate提供了懶載入的檢索策略,在沒有用到類的相關屬性時,不會發出sql從資料庫中檢索,而懶載入分為兩種:類級別的懶載入和集合的懶載入,本章先來看看類級別的懶載入檢索策略
以下是測試用的實體類:Parent,Children,他們是雙向一對多的關係,類的具體屬性如下:
//省略getter和setter,為了方便測試,請重寫toString()
public class Parent {
private Integer id;
private String name;
Set<Children> childrens = new HashSet<>();
}
public class Children {
private Integer id;
private String name;
private Parent parent;
}
兩個實體對映檔案,為節約篇幅,省略property:
//Parent.hbm.xml
<hibernate-mapping package="cn.sina.bean">
<class name="Parent" table="lazy_parent" lazy="true">
<set name="childrens" cascade="save-update" inverse="true">
<key column="pid"/>
<one-to-many class="Children"/>
</set>
</class>
</hibernate-mapping>
//Children.hbm.xml
<hibernate-mapping package="cn.sina.bean">
<class name="Children" table="lazy_children">
<many-to-one name="parent" column="pid" class="Parent"/>
</class>
</hibernate-mapping>
可以看到中將lazy=true,lazy預設的預設值就是true,我們知道get方法總是採用立即檢索策略,所以想要看到效果就要用load方法,下面我們通過程式碼測試:
@Test
public void testLazy(){
Parent parent = (Parent) session.load(Parent.class, 1);
System.out.println(parent.getClass().getSimpleName());
}
輸出:Parent_$$_javassist_0
可以看到這是一個代理物件,並沒有發出sql語句
此時我們增加一行程式碼:System.out.println(parent.getId());
得到結果:
Parent_$$_javassist_0
1
發現在沒有發出sql的情況下獲取到了ID,其實也很簡單,id是我們傳給load方法的,沒必要走資料庫
然後我們再加一行程式碼,獲取name屬性:System.out.println(parent.getName());
此時的輸出為:
Parent_$$_javassist_0
1
Hibernate:
select
parent0_.pid as pid1_0_,
parent0_.name as name1_0_
from
lazy_parent parent0_
where
parent0_.pid=?
tom
可以看到終於發出的sql語句,代理物件得到了初始化,不過請注意,本篇討論的是類級別的檢索策略,發出的sql並沒有查詢Parent的Set childrens = new HashSet<>(),這一點下一章再做討論
懶載入異常
想象一種情況,在懶載入之後,我將session關閉了,關閉之後我還想獲取到name屬性,這時會怎麼樣?
@Test
public void testLazy(){
Parent parent = (Parent) session.load(Parent.class, 1);
System.out.println(parent.getClass().getSimpleName());
session.close(); //關閉session
System.out.println(parent.getName());
}
結果當然是拋異常了
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
原因也寫的很清楚,沒session了
顯式的立即檢索
這裡主要說一個Hibernate的靜態方法:Hibernate.initialize(proxy);
看它的引數,接收的是一個代理物件,它的作用是在發生懶載入時,程式猿手動的載入
舉例說明:
Parent parent = (Parent) session.load(Parent.class, 1);
System.out.println(parent.getClass().getSimpleName());
Hibernate.initialize(parent);
結果為:
Parent_$$_javassist_0
Hibernate:
select
parent0_.pid as pid1_0_,
parent0_.name as name1_0_
from
lazy_parent parent0_
where
parent0_.pid=?
同時Hibernate.isInitialized(proxy)可以返回一個boolean值,表示代理物件是否被初始化
類級別檢索策略總結:
1.類級別的lazy屬性預設為true
2.只要在獲取類的非ID屬性時,才會發出sql語句
3.發生懶載入時,想要在session關閉之後獲取非ID屬性會發生懶載入異常(LazyInitializationException)
4.Hibernate.initialize(proxy)可以顯式的初始化代理物件