2025-02-17

  懶加載是指程序推遲訪問數據庫,這樣做可以保證有時候不必要的訪問數據庫,因為訪問一次數據庫是比較耗時的。
         一、load方法的懶加載
         先看如下代碼段
[java]
<span style="font-size:16px;">public class UserManager { 
 
    public static void main(String[] args) { 
        Users user = new Users(); 
        user.setBirthday(new Date()); 
         
        Name name = new Name(); 
        name.setFirstName("guo"); 
        name.setLastName("zhao"); 
         
        user.setName(name); 
        addUser(user); 
         
        Users users = getUser(user.getId()); 
        System.out.println(users.getName()); 
         
    } 
     
     
    static Users getUser(int id){ 
        Session session = HibernateUtil.getSession(); 
        try { 
            Users users = (Users) session.load(Users.class, id); 
            return users; 
        } finally{ 
            session.close(); 
        } 
    } 
     
    static void addUser(Users users){ 
        Session session = null; 
        Transaction tx = null; 
         
        try { 
            session = HibernateUtil.getSession(); 
            tx = session.beginTransaction(); 
 
            session.save(users); 
            tx.commit(); 
        } catch (HibernateException e) { 
            if (tx!=null) { 
                tx.rollback(); 
            } 
            throw e; 
        }finally{ 
            if(session!=null){ 
                session.close(); 
            } 
        } 
    } 
}</span> 

         上面代碼是先增加一個用戶、然後再查詢這個用戶的name組合屬性。運行上面的時候,該程序會拋出這樣一個異常:
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy – no Session這就是懶加載不能初始化異常。其原因就在於no session。在前面個持久化對象中已經說明:使用load方法時,該方法將具有延遲加載的功能,load方法並不會立即去訪問數據庫,它會返回一個代理對象,隻有當你真正去訪問這個對象的時候,它才會去訪問數據庫。
         通過上面的圖,我們看出,hibernate根本就沒有select語句,也就是說hibernate沒有去訪問數據庫,所以這個時候你去訪問它肯定是沒有的。但為什麼沒有拋出空指針異常?沒有拋出空指針異常,也就是說明User對象是存在的,那它是什麼呢?通過輸出user.getClass()可以看出是這樣一個東西:
         class com.hibernate.domain.Users_$$_javassist_5。
         這個user就是load返回的代理對象。但是這個對象並不是我們所要的。我們所要的是一個User實例對象。
         那麼怎麼解決這個問題呢?
         第一種方法:在關閉session之前訪問該對象
[java] 
<span style="font-size:16px;">    static Users getUser(int id){ 
        Session session = HibernateUtil.getSession(); 
        try { 
            Users users = (Users) session.load(Users.class, id); 
            users.getName(); 
            return users; 
        } finally{ 
            session.close(); 
        } 
    }</span> 
         不過這句話看起來會很奇怪。我們通常會采用如下的方式
[java] 
<span style="font-size:16px;">    static Users getUser(int id){ 
        Session session = HibernateUtil.getSession(); 
        try { 
            Users users = (Users) session.load(Users.class, id); 
            Hibernate.initialize(users); 
            return users; 
        } finally{ 
            session.close(); 
        } 
    }</span> 
         利用hibernate的initialize()方法將這個代理對象給初始化。
         註:在使用代理對象的getId()方法和getClass()方法的時候,並不會拋出不能初始化異常,因為這兩個屬性並不用查詢數據庫。
 
         二、在缺省的情況下,hibernate對於關聯關系會采用懶加載的方式。也就是說1-1、1-N、N-1、N-N都存在懶加載的問題。
           2.1、one-to-one懶加載
         一對一的懶加載並不常用,因為懶加載的目的是為瞭減少與數據庫的交互,從而提高執行效率,而在一對一關系中,主表中的每一條數據隻對應從表的一條數據庫,就算都查詢也不會增加多少交互的成本,而且主表不能有contrained=true,所以主表是不能懶加載的。但是從表可以有。
         實現此種懶加載必須在從對象這邊同時滿足三個條件:
            1、lazy!=false(lazy的屬性有三個選項分別為:no-proxy、false和proxy)
            2、Constrained = true ;
            3、fetch=select。
         註:當fetch設置為join時,懶加載就會失效。因為fetch的作用是抓取方式,他有兩個值分別問select和join,默認值為select。即在設為join時,他會直接將從表信息以join方式查詢到而不是再次使用select查詢,這樣導致瞭懶加載的失效。
 
         2.2、one-to-many懶加載
         與one-to-one關聯不同,對one-to-many而言,主表的每一條屬性都會對應從表的多條數據,這個時候懶加載就顯得非常有效瞭。比如一個部門裡面有多個員工,如果沒有懶加載,每查詢這個部門的時候都會查詢出多個員工,這會大大增加與數據庫交互的成本。所以Hbernate默認的是加入懶加載的。這就是查詢集合屬性的時候返回的是一個PersistentIndexed*類型對象的原因。該對象其實就是一個代理對象。當然,可以在映射文件中通過將lazy屬性設為假來禁用。
          Hibernate默認對one-to-many就是使用的懶加載,但用戶也可以取消懶加載操作:
            一:設置lazy=”false”;
            二:設置fetch=”join”.
         實現此種懶加載必須在從對象這邊同時滿足兩個個條件:
           1、lazy!=false(lazy的屬性有三個選項分別為:no-proxy、false和proxy)
           2、fetch=select。
 
           2.3、mang-to-one懶加載
         此關聯關系的懶加載和one-to-one的懶加載一樣都是可要可不要的,因為對執行效率的提高都不是非常明顯。雖然多對一與一對一關系方式相同,但是在Hibernate中多對一時,默認是進行懶加載的。另外有一點需要註意的是懶加載並不會區分集合屬性裡面是否有值,即使是沒有值,他依然會使用懶加載。
         實現此種懶加載必須在從對象這邊同時滿足兩個個條件:
             1、lazy!=false(lazy的屬性有三個選項分別為:no-proxy、false和proxy)
             2、fetch=select
 
         2.4、many-to-many懶加載
         此關聯關系的懶加載和one-to-many的懶加載一樣對程序的執行效率的提高都是非常明顯的。
         實現此種懶加載必須在從對象這邊同時滿足兩個個條件:
            1、lazy!=false(lazy的屬性有三個選項分別為:no-proxy、false和proxy)
             2、fetch=select
         能夠懶加載的對象都是被改過的代理對象,當相應的對象沒有關閉時,訪問這些懶加載對象的屬性(getId和getClass除外)hibernate會初始化這些代理,或用hibernate.initalize(proxy)來初始化代理對象;當關閉session後在訪問懶加載的對象就會出現異常

作者:chenssy

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *