延遲加載(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>沒有影響。
新聞熱點
疑難解答