1. 程式人生 > >【Hibernate】lazy延遲載入

【Hibernate】lazy延遲載入

     延遲載入(lazy load)是(也稱為懶載入)Hibernate3關聯關係物件預設的載入方式,延遲載入機制是為了避免一些無謂的效能開銷而提出來的,所謂延遲載入就是當在真正需要資料的時候,才真正執行資料載入操作。可以簡單理解為,只有在使用的時候,才會發出sql語句進行查詢。

    hibernate的lazy策略可以使用在如下四個場景:

    * <class>標籤上,可以取值:“true/false”

    * <property>標籤上,可以取值:“true/false”,但是需要類增強工具配合使用,不常用。

    * <set>/<list>標籤上,可以取值:“true/false/extra

”,對集合的延遲載入很常用。

    * <many-to-one>/<one-to-one>單端關聯標籤上,可以取值"false/proxy/noproxy"

    最常使用的地方就是在<set>/<list>集合上。

    一個Demo

public void testQuery1(){
	Session session = null;
	try{
		session = HibernateUtils.getSession();
		session.beginTransaction();
		//查詢操作,不會發出sql
		User user = (User)session.load(User.class, 1);
		
		//顯示id--(代理操作)
		System.out.println("user.id=" + user.getId());
		//顯示name -- (資料庫開始查詢操作)
		System.out.println("user.name=" + user.getName());
		
		System.out.println("user.password=" + user.getPassword());
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		
	}finally{
		HibernateUtils.closeSession(session);
	}
}
        這個例子中:
  (1)因為load預設支援lazy載入,執行session.load之後,列印user.getId();因為傳入的id,且通過代理操作,並未進行資料庫查詢,在列印user.getName()時,開始進行查詢操作。
  (2)如果Name屬性支援lazy(在hbm.xml中將該屬性設定為lazy載入),執行到"user.getName()"的時候,才會把Name值加載出來。

   現在修改這個Demo:

public void testQuery2(){
	Session session = null;
	User user = null;
	try{
		session = HibernateUtils.getSession();
		session.beginTransaction();
		
		user = (User)session.load(User.class, 1);
		session.getTransaction().commit();
		
	}catch(Exception e){
		e.printStackTrace();
		
	}finally{
		HibernateUtils.closeSession(session);
		//放在session關閉之後
		System.out.println("user.name=" + user.getName());
	}		
}
            將user.getName()方法寫到了closeSession之後,報出SessionException的錯誤,可見,hibernate中使用lazy策略,必須放到session當中。

    對Collection集合中的“lazy”策略

    通過一個Load的Demo

public void testLoad1(){
	Session session = null;
	try{
		session = HibernateUtils.getSession();
		session.beginTransaction();
		//(1)
		Classes classes = (Classes)session.load(Classes.class, 1);
		//(2)
		System.out.println("Classes.name=" + classes.getName());
		//(3)
		Set students = classes.getStudents();
		//(4)
		for(Iterator iter=students.iterator(); iter.hasNext();){
			Student student = (Student)iter.next();
			System.out.println("student.name=" + student.getName());
		}
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}
          如上,程式碼中標記了(1)(2)(3)(4)共計4條測試語句,預設的hbm.xml配置中,對<set>的lazy形式也是“true”,當呼叫testLoad1()的時候,

    不會發出sql的有:(1)(3)

    會發出Sql的有:(2)(4)

    做到了,真正的 只有在使用的時候,才會載入,即體現出lazy載入的一個好處。

    然而對於lazy="true"有一個影響效率效能的地方,參考這個demo:

public void testLoad2(){
	Session session = null;
	try{
		session = HibernateUtils.getSession();
		session.beginTransaction();
		//不會發出sql
		Classes classes = (Classes)session.load(Classes.class, 1);
		//會發出sql
		System.out.println("Classes.name=" + classes.getName());
		//不會發出sql
		Set students = classes.getStudents();
		//會發出查詢該班級全部學生的sql語句,存在效率問題
		System.out.println("count=" + students.size());
		
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}
           將for迴圈替換為查詢students.size();使用lazy="true"策略,載入過程中,對size的查詢雖然支援lazy,但是發出的sql語句是select * from t_table,改善如下
    將lazy="true"修改為lazy="extra",此時發出的sql語句為"select count(*) from t_table",提升了效率,同時extra繼承了true的所有優點,對<set>最好使用lazy="extra",當然使用lazy="false",肯定就不支援集合的延遲載入了。

    附註:<class>上的lazy策略,影響的僅僅是<property>這類普通屬性,對於<set>/<list>沒有影響。