1. 懒加载概述以及使用情景
描述:懒加载(lazy),简单说就是延时、延迟加载。
情景:在Hibernate框架应用中,就是当我们要访问的数据量过大时,使用缓存并不太合适,因为内存容量有限 ,为了减少系统资源的消耗,减少并发量,这时需要用懒加载机制来弥补这种缺陷,但是这并不意味用了懒加载总体性能就提高了。
应用:
比如学校school和学生student,学校与学生1对多,如果lazy设置为 false,那么只要加载了一个学校的信息,就会根据一对多配置的关系把所有学生的信息也加载出来。但是实际上有时候只是需要用到学校的信息,不需要用到 学生的信息,这时学生信息的加载就等于浪费资源。如果lazy设置为true,那么只有当你访问学校信息的学生信息时候才会去加载学生的信息的信息。
2. 懒加载的原理
在Hibernate中运用session进行查询时,有get()和load()两个方法,先说一下两者的区别:
这两种方法的不同就是load()拥有懒加载的特性。Load()方法就是在查询某一条数据的时候并不会直接将这条数据以指定对象的形式来返回,而是在你真正需要使用该对象里面的一些属性的时候才会去数据库访问并得到数据。他的好处就是可以减少程序本身因为与数据库频繁的交互造成的处理速度缓慢。
* session.get()
* 1、方法加载出来的对象是class对象
* 2、在session.get方法执行的时候发出sql语句
* 3、class对象是有值的
* session.load ()
* 1、方法加载出来的对象是class的代理对象
* 2、在加载其属性的时候发出sql语句(按照需求加载,延迟加载)
* 3、获取标识符(UUID)属性是不用延迟加载的,获取普通属性是需要发出sql语句的
在此以User类为例
public static void query(int id){
Session session=null;
try{
session=HibernateUtil.getSession();
User user=(User) session.load(User.class, id);
//System.out.println(user.getName());
System.out.println(user.getClass());
}catch(HibernateExceptionex){
ex.printStackTrace();
}finally{
if(session!=null){
session.close();
}
}
}
运行上述方法后,我们并没有看到Hibernate打印任何查询语句,当将注释的语句打开,可以查询到的User的name。这时我们可以看到Hibernate产生的查询语句并看到user的name属性。这就是懒加载了。
3.懒加载代理对象
通过打印user.getClass()方法来验证,打印出来的结果并不是null,其实是代理对象,而这个对象所属的类是User类的子类,是Hibernate自动实现的一个子类。
代理对象的生命周期是什么呢?
public static User query(int id){
Session session=null;
User User=null;
try{
session=HibernateUtil.getSession();
User=(User)session.load(User.class, id);
//System.out.println(User.getName());
}catch(HibernateExceptionex){
ex.printStackTrace();
}finally{
if(session!=null){
session.close();
}
}
return User;
}
//会抛出一个org.hibernate.LazyInitializationException异常
这说明懒加载的时候如果想通过代理对象查询数据库,需要在该session关闭以前才可以。但如果一定要在session关闭以后再使用代理对象的话,Hibernate中定义了一个初始化代理对象的方法initialize(),通过该方法即可将代理对象初始化。
4. 懒加载功能实现总结
1.通过Session.load()实现懒加载
load(Object, Serializable):根据id查询 。查询返回的是代理对象,不会立刻访问数据库,是懒加载的。当真正去使用对象的时候才会访问数据库。
用load()的时候会发现不会打印出查询语句,而使用get()的时候会打印出查询语句。
使用load()时如果在session关闭之后再查询此对象,会报异常:could not initialize proxy - no Session。处理办法:在session关闭之前初始化一下查询出来的对象:Hibernate.initialize(user);
使用load()可以提高效率,因为刚开始的时候并没有查询数据库。但很少使用。
2.one-to-one(元素)实现了懒加载。
在一对一的时候,查询主对象时默认不是懒加载。即:查询主对象的时候也会把从对象查询出来。
需要把主对象配制成lazy=”true” constrained=”true” fetch=”select”。此时查询主对象的时候就不会查询从对象,从而实现了懒加载。
一对一的时候,查询从对象的是默认是懒加载。即:查询从对象的时候不会把主对象查询出来。而是查询出来的是主对象的代理对象。
3.many-to-one(元素)实现了懒加载。
多对一的时候,查询主对象时默认是懒加载。即:查询主对象的时候不会把从对象查询出来。
多对一的时候,查询从对象时默认是懒加载。即:查询从对象的时候不会把主对象查询出来。
hibernate3.0中lazy有三个值,true,false,proxy,默认的是lazy=”proxy”.具体设置成什么要看你的需求,并不是说哪个设置就是最好的。在与标签上:当为true时,会有懒加载特性,当为false时会产生N+1问题,比如一个学生对应一个班级,用一条SQL查出10个学生,当访问学生的班级属性时Hibernate会再产生10条SQL分别查出每个学生对应的班级.
lazy= 什么时候捉取
fetch= 捉取方式:select=关联查询;join=连接表的方式查询(效率高)
fetch=join时,lazy的设置将没有意义.
4. one-to-many(元素)懒加载:默认会懒加载,这是必须的,是重常用的。
一对多的时候,查询主对象时默认是懒加载。即:查询主对象的时候不会把从对象查询出来。
一对多的时候,查询从对象时默认是懒加载。即:查询从对象的时候不会把主对象查询出来。
需要配置主对象中的set集合lazy=”false” 这样就配置成是不懒加载了。或者配置抓取方式fetch=”join”也可以变成不懒加载。