您的位置:首页 > 其它

【Hibernate】lazy延迟加载

2017-02-09 11:15 267 查看
     延迟加载(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>没有影响。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: