hibernate 中lazy作用

轉載: 

 

HIBERNATE的持久化對象加載策略。
延遲加載, 也就是用到的時候纔去加載.這樣可以提高一些性能.
Hibernate
lazy loading 採用了一個HibernateSession來管理session,它的邏輯是每進行一次數據庫操作,就開新的session,操作完成後立即關閉該session。這樣做的好處是可以嚴格關閉session,避免菜鳥級的錯誤,但是hibernate.org並不推薦這麼做。因爲這不適合lazy loading,也不適合跨方法的事務。

比如在我們的應用中,user->post形成一對多的映射,User中有一個包含postList

User中,有多個屬性:namepasswordphone等,還有一個List類型的posts。當我們對posts使用lazy laoding的時候,hibernate會在獲得User對象的時候,僅僅返回name,password,phone等基本屬性,當你訪問posts的時候,它纔會從數據庫中提取posts需要的數據,這就是所謂lazy laoding。但是在我們的系統中,session是被立即關閉的,也就是在讀取了name,password,phone等基本屬性後,session已經close了,再進行lazy loaiding
就會有異常。
解決辦法是在close session之前,調用Hibernate.initialize(user.getPosts()),告訴系統,user.getPosts()是需要lazy laoding的。但是這樣做會破壞HibernateSession
類的封裝.
後來採用所謂的OpenSessionInView模式,把session的週期交給servlet filter來管理,每當有request進來,就打開一個sessionresponse結束之後再關閉它,這樣可以讓session存在於整個請求週期中。

本文主要針對一對多情況下讀取父類的子集合時,hibernate 的lazy屬性在其中的影響進行總結。(以下代碼運行在jdk1.5,jboss eclipse ide 1.5,hibernate 3.1環境下)
假設有:父類 Person   (含有Set類型屬性Address),
                 子類 Address(碰巧集合的名字和子類的名字都是Address,不要混淆了)
                  Person.hbm.xml   主要片段:
         <id
             name="idx"
             column="idx"
             type="long"
         >
             <generator class="identity">
             </generator>
         </id>
         <property
             name="age"
             type="int"
             update="true"
             insert="true"
             column="age"
         />
         <property
             name="name"
             type="java.lang.String"
             update="true"
             insert="true"
             column="name"
         />
         <set
             name="address"
             table="address"
             lazy="true"
             cascade="none"
             sort="unsorted"
         >
             <key
             >
                 <column
                     name="personidx"
                 />
             </key>
             <one-to-many
                   class="com.abc.common.pojo.Address"
             />

         </set>
     (1)在session 的週期內,無論lazy 設爲true or false, 不會有任何限制。訪問父子數據的代碼如下所示 :       
      //打開session  
      session = HibernateUtil.currentSession();

      PersonDAO dao = new PersonDAO();
      Person person = null;

      person = (Person)dao.findByPrimaryKey(4);
      Set addressSet = person.getAddress();

     Address[] addressAry = new Address[addressSet.size()];
     Address address = null ;
     addressSet.toArray(addressAry);
    
     for(int i=0 ;i<addressAry.length;i++){
                     ................      
      }
    //session關閉
     session.close();
      if (session.isOpen()){
           HibernateUtil.closeSession();
     }

(2)在session的週期外,訪問父子數據的代碼如下所示 :
      //打開session  
      session = HibernateUtil.currentSession();

      PersonDAO dao = new PersonDAO();
      Person person = null;

      person = (Person)dao.findByPrimaryKey(4);
      /**********************
       *留待後續處理
       *********************/
      session.close();
    
      //session關閉之後才訪問person的子集
      Set addressSet = person.getAddress();

     Address[] addressAry = new Address[addressSet.size()];
     Address address = null ;
     addressSet.toArray(addressAry);
    
     for(int i=0 ;i<addressAry.length;i++){
                     ................      
      }
      if (session.isOpen()){
           HibernateUtil.closeSession();
     }

    此時,上述代碼的運行結果根據lazy的設置的不同而不同
lazy=false
    結果:可以訪問得到Person和Address的數據
lazy= true
     根據代碼的寫法有不同
     (1)代碼其他處不做任何處理,則拋出異常
          org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
          。。。。。。
     (2)如果做一些處理如下,將上述那段代碼中的"留待後續處理"換成以下代碼
            Hibernate.initialize(person.getAddress());   則可以訪問得到Person和Address的數據
          實際編寫時,不會象上述這樣的寫法,即將
          Hibernate.initialize(person.getAddress());和person.getAddress()在同一個方法裏面調用。他們往往出現在應用程序的不同層次中(前者出現在DAO層居多,而後者則出現在web層居多).

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章