- 【版权所有,文章允许转载,但须以链接方式注明源地址,否则追究法律责任】
为什么hibernate需要延迟加载?
通过关联关系可以在程序中方便地获取关联对象的数据,但是如果从数据库中加载Student对象时,就同时自动加载所有关联的Grade对象,而程序实际上仅仅需要访问Student对象时,那么这些关联的Grade对象就白白浪费了许多内存空间。Hibernate查询Student对象时,立即查询并加载与之关联的Grade对象,这种查询策略就叫做立即加载。但是立即加载有两大不足:
<1> 会执行不必要的查询语句,影响查询性能。
<2> 可能会加载大量不需要的对象,增加系统开销,浪费内存空间。
为了解决以上问题,Hibernate就提供了延迟加载策略。延迟加载策略能避免加载应用程序不需要访问的关联对象。就以Student类和Grade类为例,介绍如何设置加载策略,以优化查询性能。
Hibernate允许在对象-关系映射文件中使用lazy属性配置加载策略,并且分为类级和关联级两个级别,分别进行控制。看下表:
级 别 | Lazy属性取值 |
---|---|
类级别 | <class> 元素中lazy属性的可选值为true(延迟加载) 和 false(立即加载) 。默认值为true |
一对多关联级别 | <set> 元素中lazy属性的可选值为true(延迟加载)、extra(增强延迟加载)、false(立即加载)。默认值为true |
多对一关联级别 | <many-to-one> 元素中lazy属性的可选值为proxy(延迟加载)、no-paoxy(无代理延迟加载)和false(立即加载)。默认值为proxy |
大家看完表可以发现,不管哪个级别默认都是延迟加载的查询策略,以减少系统资源的开销!
类级别的查询策略
类级别的默认加载策略就是延迟加载,所以你不写lazy属性也可以。例如:
<class name="cn.pojo.Student" table=" STUDENT ">
划重点本人自己总结:实体类对象目的是访问他的属性,用立即加载。实体类对象目的仅仅是获得他的引用,用延迟加载。
一对多和多对多的关联查询策略
先写个示例代码:
<hibernate-mapping>
<class name="cn.hibernatedemo.entity.Dept" table="`DEPT`">
<id name="deptNo" column="`DEPTNO`" type="java.lang.Byte">
<generator class="assigned"/>
</id>
<property name="deptName" type="java.lang.String" column="`DNAME`"/>
<property name="location" type="java.lang.String">
<column name="`LOC`"></column>
</property>
<set name="emps" inverse="true" lazy="true">
<key column="`DEPTNO`"></key>
<one-to-many class="cn.hibernatedemo.entity.Emp"/>
</set>
</class>
</hibernate-mapping>
这两种查询策略用的都是set元素,所以lazy属性在set元素中设置,<set>
标签的lazy属性取值决定了emps集合被初始化时机(就是说到底是在加载Dept对象时就被初始化,还是在程序访问emps集合是被初始化)看下表lazy属性的取值:
lazy属性值 | 加 载 策 略 |
---|---|
true | 默认值,延迟加载 |
false | 立即加载 |
extra | 增强延迟加载 |
1.立即加载
很多情况下,应用程序并不需要访问这些emp对象,所以在一对多关联级别中不能随意使用立即加载策略!
2.延迟加载
对于set元素而言,应该优先考虑默认的延迟加载策略,直接不写lazy属性就可以,例如:
<set name="emps" inverse="true" >
<key column="`DEPTNO`"></key>
<one-to-many class="cn.hibernatedemo.entity.Emp"/>
</set>
3.增强延迟加载
<set name="emps" inverse="true" lazy="extra">
<key column="`DEPTNO`"></key>
<one-to-many class="cn.hibernatedemo.entity.Emp"/>
</set>
增强延迟加载与一般的延迟加载主要区别在于,增强延迟加载能进一步延迟Dept对象的emps集合代理类实例的初始化时机。当程序第一次访问emps属性的iterator()方法时,会导致emps集合代理类实例的初始化,而当程序第一次访问emps属性的size()、contains()和isEmpty()方法时,Hibernate不会初始化emps集合的代理实例,仅通过特定的select语句查询必要的信息。以下代码演示了增强延迟策略在hibernate运行时的行为:
tx=session.beginTransaction();
Dept dept=(Dept) session.get(Dept.class,new Byte("10"));
//以下语句不会初始化emps集合类实例
//执行sql语句:select count(empNo) from emp where DEPTO=?
dept.getEmps().size();
//以下语句不会初始化emps集合类实例
//执行SQL语句:select * from emp where DEPTO=?
dept.getEmps().iterator();
tx.commit();
多对一关联查询策略
在映射文件中度偶对一是用<many-to-one>
标签设置的,看下表:
lazy属性值 | 加 载 策 略 |
---|---|
proxy | 默认值,延迟加载 |
no-proxy | 无代理延迟加载 |
false | 立即加载 |
多对一也是默认延迟加载,与前边不同的是它默认加载的属性值是proxy,并且它的属性没有true了。那么什么情况下使用哪种加载呢? | |
划重点:应用程序仅仅访问emp对象,并不需要与他关联的dept对象时,就用默认的延迟加载即可! | |
注意:第二个属性无代理延迟加载,需要在编译期间进行字节代码增强操作,否则运行情况和延迟加载一样,所以很少会用到。 |
【创作不易,帮助到你的话点个赞谢谢】