4.懒加载:
在前面我们已经对懒加载有所提及,现在再借助一个简单的实例(它们均位于lazyLoad项目下)再来重新认识懒加载:先看下面的代码:
package com.asm.hibernate.test; public class UserTest2 { public static void main(String[] args) { addUser(); User u = getUser(1); System.out.println("return type:" + u + "\t name=" + u.getName()); } static User getUser(int id) { Session s = null; try { s = HibernateUtil.getSession(); User user = (User) s.load(User.class, id); // 以下的两种方式都可以让懒加载去真正连接数据库。 Hibernate.initialize(user); // System.out.println(user.getName()); System.out.println("load--User:" + user.getClass()); return user; } finally { if (s != null) s.close(); } } static void addUser() { 省略内容:此方法的作用就是插入一条记录到数据库中,以使我们的查询操作可以进行。 } }
执行后,打印结果如下:
load--User:class com.asm.hibernate.domain.User$$EnhancerByCGLIB$$212cbff4
return type:com.asm.hibernate.domain.User@1f6ba0f name=jack
注意到上面第一行打印结果,可以发现返回的是User的一个子类,借此来看看懒加载的实现,懒加载的意思是只有当我们真正要查询的数据时,它才真正去连接数据库,为什么要提出懒加载呢,我们知道数据库的连接是非常耗资源的,有了懒加载可以从一定程度上降低数据库连接资源的消耗。 懒加载本质是借助asm.jar和cglib.jar这两个jar包,来生成User的一个子类,这就是前面提到“使用懒加载时实体类不能是final”的原因,从这里我们知道hibernate用构建实体类的子类来实现一个更强大的操作功能,这样即使数据库无记录,查询返回的结果对象也永远不会为null,即是说“返回的结果对象==null”永远不能成立,但这并不表示一定查询出了结果。其实如果我们以懒加载查询的结果为空,而我们再对这个对象进行操作时,是会报错得。 概述要点:(1)hibernate构造了实体类的子类来查询(2)要使用赖加载,实体类不能声明为final (3)查询结果对象永不为空。(4)只要连接未关,如果我们想获知此对象的任何属性信息都会引起懒加载去连接数据库,但是如果我们是企图获取它的id时,却不能让hibernate去连接数据库。
补充说明:其实这种懒加载的使用很少,它通常在需要关联两个实体对象时使用,比如我们希望把查询出的User user对象关联到部门中去时,即我们 Employee emp=new Employee(); emp.setUser(user);在这种情况下我们并不关心它的查询内容,只是想关联到部门中去,所以此时使用懒加载是一个节省“数据库连接资源”的好方法。
5.概述关联关系中的懒加载:
(1)一对一中的懒加载:必需要同时满足三个条件才能实现懒加载:即在<one-to-ont> 元素中配置lazy!=false(即是为true或proxy);constrained=true;fetch=select,但在主表中不会有懒加载,因为主表不能满足constrained=true;其实在主外键关联的“一对一“关联关系中,我们判断主表和从表也是从是否配置“constrained“来判断:因为constrained的配置只会在从表中出现。从上面的分析中可以得知:查询主表永不会使用懒加载,查询从表可选择懒加载。下面再结合fethch来分析查询从对象时的懒加载:
|
fetch=join |
fetch=select |
lazy=true |
由于采取的是join连接查询,所以会一次关联所有的表查出所有数据,这样懒加载失效。 |
懒加载有效,实际查询从对象发展时,才去连接数据库。 |
lazy=false |
=false意为不使用懒加载。 |
|
lazy=proxy |
默认设置:使用代理实现懒加载。 |
提示:fetch的意思是“通过什么方式抓取”,lazy的意思是“什么时候抓取”。“抓取”
意为“获得数据,连接数据库”。 其实在“一对一”中使用懒加载对性能提升不多大的作用。
分析“查询主对象不能使用懒加”:当我们要想获取一个主对象时,仅从查询主表是不能判断出是否有从对象,比如我们在查询主表获取Person对象时,不能从主表中查出是否有有“身份证号“,这样我们便不能正确设置Person对象的身份证属性,所以hibernate采取了连接查询,这也就是为什么主对象不能使用懒加载的原因。但是查询从对象可使用懒加载,原因如下:当我们通过查询从表获知从对象时,可以在从表的主外键中查询这个身份证号是否有Person对象对应,如果没有,设它的person属性为null,如果有我们放置一个代理,当要真正查询时,便通过这个代理来查询。
(2)其它关联关系使用懒加载的条件:在实配置文件中的“关联关系配置”配置元素中配置时满足以下两个条件:lazy!=false;fetch=select
(3)强调:能够懒加载的对象都是被必定过的代理对象,当相关联的session没有关闭时,访问这些懒加载对象(代理对象)的属性会初始化这些代理(便getId和getClass除外)对象,当相关的session关闭后,再访问懒加载对象将会出现异常“could not initialize proxy - no Session”。
(4)灵活选择:在查询方法是我们有时候希望使用代理懒加载,但有时候我们可能又要具体查询出数据。我们可以这样做来灵活选择:
public Object query(int id,boolean signLazy){
....
if(signLady)
Hibernate.initialize(代理对象);
说明:为true,则会初始化代理,连接数据库,且在此方法调用完成后得到的对象是可以进行有关此对象的属性访问得。为false,则不会去真正连接数据库,只是为了建立起某种关联关系服务
....
}
(5)简单的属性也可以使用懒加载,但效果不大,除非是用在大的文本段。