Hibernate之lazy延遲加載

一.延遲加載的概念html

   當Hibernate從數據庫中加載某個對象時,不加載關聯的對象,而只是生成了代理對象,獲取使用session中的load的方法(在沒有改變lazy屬性爲false的狀況下)獲取到的也是代理對象,因此在上面這幾種場景下就是延遲加載。sql

二.理解當即加載的概念數據庫

  當Hibernate從數據庫中加載某個對象時,加載關聯的對象,生成的實際對象,獲取使用session中的get的方法獲取到的是實際對象。session

三.爲何要使用延遲加載性能

  延遲加載策略能避免加載應用程序不須要訪問的關聯對象,以提升應用程序的性能。.net

四.當即加載的缺點代理

Hibernate在查詢某個對象時,當即查詢與之關聯的對象,咱們能夠看出這種加載策略存在兩大不足:xml

1.select的語句數目太多,須要頻繁的訪問數據庫,會影響查詢的性能。htm

2.在應用程序只須要訪問要的對象,而不須要訪問與他關聯的對象的場景下,加載與之關聯的對象徹底是多餘的操做,這些多餘的操做是會佔內存,這就形成了內存空間的浪費。對象

五.何時使用延遲加載何時使用當即加載

   若是程序加載一個持久化對象的目的是爲訪問他的屬性,則能夠採用當即加載。若是程序加載一個持久化對象的目的僅僅是爲了得到他的引用,則能夠採用延遲加載。

六.Hibernate在對象-關係映射問價中配置加載策略

   I.類級別:

      <class>元素中lazy屬性的可選值爲true(延遲加載)和false(當即加載);

      <class>元素中的lazy屬性的默認值爲true

   II.一對多關聯級別:

      <set>元素中的lazy屬性的可選值爲:true(延遲加載),extra(加強延遲加載)和false(當即加載);

      <set>元素中的lazy屬性的默認值爲true

   III.多對一關聯級別:

      <many-to-one>元素中lazy屬性的可選值爲:proxy(延遲加載),no-proxy(無代理延遲加載)和false(當即加載)

      <many-to-one>元素中的lazy屬性的默認值爲proxy

   在下面的一些案例中都會以員工(Emp)的部門(Dept)的例子講解:

   員工和部門是多對一的關係:

   關於員工和部門的Hibernate配置就不囉嗦了:能夠看個人這篇博客:http://www.cnblogs.com/heyongjun1997/p/5767187.html

I.1類級別的查詢策略:

   01.當即加載案例:

     需求:經過Session的load()方法加載Dept對象時:

     首先在Dept.hbm.xml文件中配置lazy屬性爲false,表示當即加載。

 

 

複製代碼

@Test

public void loadDept() {

// 獲取Session對象

Session session = HibernateUtil.currentSession();

// 若是經過load方式加載Dept對象

Dept dept=(Dept)session.load(Dept.class, 12);

      // 關閉session

HibernateUtil.closeSession();

}

複製代碼

 

   咱們知道使用Load方法加載的是代理對象,只會在屬性裏保存一個OID,可是若是在Dept映射文件中配置了類級別的lazy爲false就表明加載該對象時當即加載,也就是當即檢索一道數據庫,發出sql:

 

 

       02.延遲加載案例:

        一樣是獲取Dept對象,可是要把Dept.hbm.xml配置文件的類級別的lazy屬性改成lazy=」true」 或者不寫,應爲類級別的lazy屬性默認就是true,

 

 

複製代碼

@Test

public void loadDept() {

// 獲取Session對象

Session session = HibernateUtil.currentSession();

// 若是經過load方式加載Dept對象

session.load(Dept.class, 12);

// 關閉session

HibernateUtil.closeSession();

}

複製代碼

 

  此時Dept.hbm.xml配置文件的類級別的lazy屬性爲true,則是延遲加載,那麼load方法獲取的知識Dept的代理對象,因此他不會去檢索數據庫。

 

 

II.1一對多和多對多關聯的查詢策略

  01.當即加載案例:

     在獲取部門對象的時候同時獲取員工對象:

設置Dept.hbm.xml 類級別的lazy屬性爲false;表示當即加載:

設置<set>元素的lazy屬性爲false,表示在加載部門的同時當即加載員工:

 

 

複製代碼

@Test

public void loadDept() {

// 獲取Session對象

Session session = HibernateUtil.currentSession();

// 若是經過load方式加載Dept對象

Dept dept=(Dept)session.load(Dept.class, 12);

// 關閉session

HibernateUtil.closeSession();

}

複製代碼

  控制檯輸出結果:

 

 當你想獲取一的一方(Dept)的對象同時,你也要加載多的一方(Emp)的對象,那麼你要在一的一方(Emp)的<set>的節點上加上lazy="false"表示當即加載,因此在使用Load方式加載Dept對象的時候,Emp對象也會不加載出來,因此程序在運行到Dept dept=(Dept)session.load(Dept.class, 12);會發出兩條sql語句:

第一條是查詢部門的信息,第二條sql是根據部門編號去數據庫中檢索員工信息。

  02.延遲加載:

      若是把上面的案例<set>節點的屬性lazy改成trur,或者默認不寫,那麼在加載Dept對象的時候,就不會再去加載Emp對象,並且只會發出一條sql,這條sql就是指檢索部門的信息。

 

      03.加強延遲加載:

   當<set>元素中配置lazy的屬性爲extra,代表是加強延遲加載策略。

 

  其實加強延遲加載策略與通常的延遲加載策略lazy="true"很是類似。他們主要區別在於,咱們看到這個名詞加強延遲加載,顧名思義就是這個策略能在進一步的幫我延遲加載這個對象,也就是代理對象的初始化時機。

     演示案例:

         01. 當set節點的lazy屬性爲true,或者不寫的話(取默認值),那麼執行如下語句:

           

複製代碼

@Test
    public void loadDept() {
        // 獲取Session對象
        Session session = HibernateUtil.currentSession();
        // 若是經過load方式加載Dept對象
        Dept dept=(Dept)session.load(Dept.class, 12);
        //拿該部門下的員工的人數:也就是集合的大小
        dept.getEmps().size();
        // 關閉session
        HibernateUtil.closeSession();
    }

複製代碼

      輸出結果:

    

 

      02. 當set節點的lazy屬性爲extra那麼執行如下語句:

       

複製代碼

@Test
    public void loadDept() {
        // 獲取Session對象
        Session session = HibernateUtil.currentSession();
        // 若是經過load方式加載Dept對象
        Dept dept=(Dept)session.load(Dept.class, 12);
        //拿該部門下的員工的人數:也就是集合的大小
        dept.getEmps().size();
        // 關閉session
        HibernateUtil.closeSession();
    }

複製代碼

     輸出結果:

     

 

    III.1多對一關聯的查詢策略

         在映射文件中,<many-to-one>元素用來設置多對一的關係,在Emp.hbm.xml文件中代表Emp類到Dept類的多對一的關聯關係:

    

 

     01.延遲加載

        需求:獲取Emp對象,可是並不去加載與之關聯的Dept對象。

       首先要設置<many-to-one>節點的lazy屬性爲proxy,表示延遲加載。

      

複製代碼

@Test
public void loadEmp() {
// 獲取Session對象
Session session = HibernateUtil.currentSession();
// 若是經過load方式加載Dept對象
Emp emp=(Emp)session.get(Emp.class, 1);

//獲取Dept對象,由於此時的配置文件lazy是proxy,因此是代理對象
Dept dept=emp.getDept();
// 關閉session
HibernateUtil.closeSession();
}

複製代碼

      控制檯輸出結果:

      

 

    結果你們可想而知:<many-to-one>節點的lazy屬性爲proxy,表示延遲加載。在加載Emp對象的時候會發出sql去查詢數據庫,可是在獲取Dept對象的時候延遲加載了,因此不會發出sql。

     

       02.無代理延遲加載:

 

            在<many-to-one>元素中配置lazy屬性爲no-proxy,表示無代理延遲加載。

             

        

複製代碼

@Test
public void loadEmp() {
// 獲取Session對象
Session session = HibernateUtil.currentSession();
// 若是經過load方式加載Dept對象
Emp emp=(Emp)session.get(Emp.class, 1);

//獲取Dept對象,由於此時的配置文件lazy是proxy,因此是代理對象
Dept dept=emp.getDept();
// 關閉session
HibernateUtil.closeSession();
}

複製代碼

            此程序在加載的Emp對象dept屬性爲NULL,當程序運行到第3行的時候將觸發Hibernate執行查詢Dept表的select語句,,從而加載Dept對象,因而可知,當lazy屬性爲proxy時,能夠延長延遲加載Dept代理對象的時間,而lazy屬性爲no-proxy時,則能夠避免使用由Hibernate提供的Dept代理類實例,是Hibernate對程序提供更加透明的持久化服務。

     03.當即加載:

          首先要設置<many-to-one>節點的lazy屬性爲false,表示當即加載。

          

           

複製代碼

@Test
public void loadEmp() {
// 獲取Session對象
Session session = HibernateUtil.currentSession();
// 若是經過load方式加載Dept對象
Emp emp=(Emp)session.get(Emp.class, 1);

//獲取Dept對象,由於此時的配置文件lazy是false,因此是實際對象
Dept dept=emp.getDept();
// 關閉session
HibernateUtil.closeSession();
}

複製代碼

    控制檯輸出結果:

       

相關文章
相關標籤/搜索