1. 程式人生 > >Hibernate深入學習(四):類級別的檢索策略

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)可以顯式的初始化代理物件