Hibernat加载策略有两种,分别为即时加载和延迟加载(懒加载或者lazy),get使用的是即时加载,使用get获取数据时会立即查找(会先去缓存查找,如果缓存中没有找到,才会去数据库中查找),而load使用的为延迟加载,不会立即去查询,当需要的时候才会去查找,而且load获取到的类型不是查找的类型,而是一个代理类型。本文主要学习延迟加载。
1.首先将表与pojo类创建好,建立好映射关系
2.写测试方法
这里为了比较,写一个get方法,写一个load方法。
经过debug发现,get方法在执行时直接去查找数据库,而load方法是在调用book.getName()时才去查询数据库,而且get方法获得的返回值为Book类型,而load方法返回值为一个代理类,并且如果将book.getName()改为book.getId(),get方法依旧会去查询数据库,而load方法不会。
如果将以上代码进行修改,将输出语句修改到session关闭以后。
如果进行这样的修改,get方法依旧会正常执行,正常查询数据库,而load方法则会抛出异常:lazy初始化异常,不能初始化代理,没有session。因为load只有在使用时才会去查询,此时session已经关闭,所以无法初始化代理,所以抛出异常。
3.class的lazy
1)class中用一个lazy属性,它的默认值为true,也就是说class本身默认为延迟加载。
如果将lazy修改为false,将延迟加载关闭,执行上面的load方法,发现不会抛出异常,而进行debug发现,在执行load方法时直接查询了数据库,而返回的类型也不再是代理类型,而是Book类型,也就是说,如果要使用hibernate的延迟加载需要将class中的lazy设置为true,以前没有设置是因为class的lazy本身默认为true。
4.多端关联关系的lazy(list,set)
上面都说的是单表的lazy,下面说一下关联关系的lazy。(创建Book与Category之间的关系)
经过debug发现,在执行get时,只是去数据库查询了category的信息,而没有去查询book的信息,但是在执行iterator.next().getBookName()时去查询了book的信息,但是get为即时加载,为什么在这里会进行延迟加载呢?经过查询发现原来配置关系的set,list等默认为懒加载,即延迟加载。
如果在此将set中的lazy的值设置为false,则在查询category时直接会发出2条sql语句,直接将set中的值查询出来。、
注意:当set中lazy=true时,支持延迟加载,但是使用size方法时依旧会查询整个set集合,当set中lazy=extra时,比较智能,支持延迟加载,但是使用size方法时,sql语句中使用的是count语句,而不是查询所有。
5.单端关联上的lazy(many-to-one,one-to-one)
这里lazy有三个值,false,proxy,no-proxy,这里默认为proxy,支持延迟加载,使用时调用代理,查询数据。如果设置为false则立即加载,而no-proxy是不使用代理,这里需要使用第三方插件增强它才可以使用,这里就不做演示。
6.property的lazy
其实property也是支持延迟加载的,但是其中默认lazy=false,当lazy=true时需要使用第三方插件增强,才可以使用。一般不会将property的lazy设置为true,当使用大对象时才会使用。
总结:load支持延迟加载,get不支持延迟加载,如果没有设置延迟加载,那么load也会立即加载对象。
注:本文是在学习期间根据网上视频写的学习笔记,如有侵权请联系删除!