【Hibernate】lazy延遲載入
阿新 • • 發佈:2019-02-04
延遲載入(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:
將user.getName()方法寫到了closeSession之後,報出SessionException的錯誤,可見,hibernate中使用lazy策略,必須放到session當中。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()); } }
對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>沒有影響。