延迟加载(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>没有影响。
新闻热点
疑难解答