Hibernate 配置详解(3)
7) hibernate.max_fetch_depth:
该属性用于设置left out join单对象查询关系(one-to-one/many-to-one)中最大的关联深度。默认值为0,即默认情况不使用out-join(而使用延迟加载),建议的取值为0-3之间。
要理解max_fetch_depth属性,就必须要理解在one-to-one/many-to-one元素上的out-join属性。我们用下面的一个例子来说明:
public class Department {
private Long id;
private String name;
private Employee manager;
} public class Employee {
private Long id;
private Department dept;
}
在Employee对象中有一个dept属性代表员工所属的部门,而在Department对象中有一个manager属性代表部门的管理员,按照正常的映射:
<class name="Department">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
<many-to-one name="manager" class="Employee"/>
</class> <class name="Employee">
<id name="id">
<generator class="native" />
</id>
<many-to-one name="dept" column="DEPT_ID"/>
</class>
那么,通过get/load方法无论是得到Department对象再得到对应的manager,或者得到Employee对象再得到对应的dept,hibernate默认都会采用延迟加载得到对应的manager/dept。这个就是我们说的,默认情况下,在many-to-one中,通过many方得到one方,采用延迟加载策略。但是我们也知道,使用延迟加载,会导致额外的SELECT产生,特别是在查询的时候,容易产生N+1问题,所以,我们可以使用适当的fetch策略来修改hibernate加载对象的方式。我们以下只讨论many-to-one的fetch属性及策略(以Employee中的dept属性为例):
1,join:在一条SQL中使用LEFT OUT JOIN直接查询出many方和对应的one方
加载策略:直接使用一条left out join把Employee对应的Department对象查询出来,没有延迟加载:
select employee0_.id as id1_1_1_, employee0_.DEPT_ID as DEPT2_1_1_, department1_.id as id1_0_0_, department1_.name as name2_0_0_, department1_.manager as manager3_0_0_ from Employee employee0_ left outer join Department department1_ on employee0_.DEPT_ID=department1_.id where employee0_.id=?
2,select:再两条SQL中分别使用SELECT查询出many方和对应的one方
加载策略:使用延迟加载,使用另一条SELECT语句查询出Employee对应的Department对象。
可以看到,使用fetch=”join”就可以缓解N+1问题,减少SQL。理解到这个,就可以理解到out-join属性。在many-to-one上还有一个outer-join属性,outer-join的取值可以为auto,false,true,默认值为auto(可以想象为false),即不使用LEFT OUT JOIN,如果设置为true,就相当于fetch=”join”,在一条SQL中使用LEFT OUT JOIN直接查询出many方和对应的one方。当然,这还需要看fetch属性的取值,比如fetch=”select”,就算outer-join=”true”,也会使用延迟加载,因为fetch规定的是获得关联对象的方式,而outer-join只是规定是否用LEFT OUT JOIN获取关联对象,所以我简单理解为fetch的级别高于outer-join(个人理解方式)。
理解到outer-join的好处之后,问题接着就来了,我们可以看到,假如在Employee方的dept设置为outer-join为true,那么在得到Employee的时候,就会立刻使用LEFT OUT JOIN取得对应的Department对象,那如果Department对象的manager属性的outer-join也设置为true,那么在得到Department对象时,又会立刻使用LEFT OUT JOIN关联到Employee表,如果大量的关联对象都设置了outer-join属性,那么在得到一个对象的时候,就会引起大量的表的外连接查询,导致查询效率也会非常慢,在这种情况下,就可以通过设置hibernate.max_fetch_depth来限制外链表的数量。比如:
<class name="Department">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
<many-to-one name="manager" class="Employee" outer-join="true"/>
</class> <class name="Employee">
<id name="id">
<generator class="native" />
</id>
<many-to-one name="dept" column="DEPT_ID" outer-join="true"/>
</class>
如果没有设置hibernate.max_fetch_depth,就会使用两个LEFT OUT JOIN把Employee,Employee对应的department,department对应的manager都查询出来:
select employee0_.id as id1_1_2_, employee0_.DEPT_ID as DEPT2_1_2_, department1_.id as id1_0_0_, department1_.name as name2_0_0_, department1_.manager as manager3_0_0_, employee2_.id as id1_1_1_, employee2_.DEPT_ID as DEPT2_1_1_ from Employee employee0_ left outer join Department department1_ on employee0_.DEPT_ID=department1_.id left outer join Employee employee2_ on department1_.manager=employee2_.id where employee0_.id=?
如果设置:
hibernate.max_fetch_depth 1
那么就只会使用一条LEFT OUT JOIN只查询出Employee和employee对应的department:
select employee0_.id as id1_1_1_, employee0_.DEPT_ID as DEPT2_1_1_, department1_.id as id1_0_0_, department1_.name as name2_0_0_, department1_.manager as manager3_0_0_ from Employee employee0_ left outer join Department department1_ on employee0_.DEPT_ID=department1_.id where employee0_.id=?
同样,这个参数对fetch=”join”的情况也适用。
另外,如果是通过查询:
session.createQuery("FROM Employee").list(); session.createCriteria(Employee.class).list();
那么,只有当使用Criteria的方式查询,fetch或者outer-join才会起作用,而使用Query对象查询,是只会查询出Employee的。这点需要非常注意。
Hibernate 配置详解(3)的更多相关文章
- Hibernate 配置详解(9)
hibernate.cache.use_structured_entries Hibernate文档上介绍,该属性是用于把对象以一种更易读的方式放到二级缓存中,这样,在对二级缓存进行监控的时候就更容易 ...
- Hibernate 配置详解(2)
6) hibernate.session_factory_name: 配置一个JNDI名称,通过Configuration对象创建的SessionFactory会绑定到JNDI下该名称中.一般名字格式 ...
- Hibernate 配置详解(5)
9) hibernate.batch_fetch_style: 该配置是hibernate4.2.0新添加的,使用这个设置可以配置hibernate在做batch-fetch的时候,生成SQL的策略. ...
- Hibernate 配置详解(8)
hibernate.generate_statistics 这个配置大家应该都很熟悉,用于开启Hibernate统计信息,便于对Hibernate相关性能调试提供数据依据.在开发过程当中,可以把这个选 ...
- Hibernate 配置详解(12) 补充
hibernate.hbm2ddl.import_files_sql_extractor 这个配置项用于补充这篇文章: http://blog.csdn.net/stefwu/article/deta ...
- Hibernate 配置详解(12) 其实我也不想用这么土的名字
hibernate.hbm2ddl.import_files 这个配置用于在hibernate根据映射文件执行DDL之前,如果我们自己设置了要事先运行的SQL文件,hibernate就会先执行这些SQ ...
- Hibernate 配置详解(7)
hibernate.order_updates: Hibernate文档中提到,该配置用于在刷新一级缓存,提交UPDATE的时候,按照每类对象的主键顺序排序后再提交,可以在高并发情况下减少事务死锁的可 ...
- Hibernate 配置详解(11)
hibernate.session_factory_name_is_jndi 配置hibernate.cfg.xml中SessionFactory的name属性是否作为JNDI名称绑定.默认是true ...
- hibernate二级缓存ehcache hibernate配置详解
<!-----------------hibernate二级缓存ehcache------------------------->hibernate配置 <prop key=&quo ...
- Hibernate配置详解
<!--标准的XML文件的起始行,version='1.0'表明XML的版本,encoding='gb2312'表明XML文件的编码方式--> <?xml version='1.0' ...
随机推荐
- 虚拟化技术性能总结:Zones, KVM, Xen
[译]虚拟化技术性能总结:Zones, KVM, Xen 时间 2014-04-29 16:52:44 Babyfacer_陈晓炜 原文 http://blog.csdn.net/babyface ...
- 一次优化web项目的经历记录(一)
一次优化web项目的经历记录 这段时间以来的总结与反思 前言:最近很长一段时间没有更新博客了,忙于一堆子项目的开发,严重拖慢了学习与思考的进程.开水倒满了需要提早放下杯子,晚了就会烫手,这段时间以来, ...
- iOS UIKit:view
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css); @import url(/ ...
- 当升级新版本的时候,从新加载新版本的js的方法
<script src="../Script/SmcScript.js?version='<%=Smc20.Web.WebForm.Public.WebConst.WEBJSCA ...
- onContextItemSelected 用法
http://blog.csdn.net/kavensu/article/details/8045041 onCreateOptionsMenu :此方法为创建菜单方法,这个菜单就是你在点击手机men ...
- 借用Toad 生成表空间的使用量图示
图示产生方法 图示(tablespace uage)如下
- 关于cocoapods和swift中使用oc第三方
mac 系统自带ruby,使用cocoapods,直接安装cocoapods就行 终端:$ sudo gem install cocoapods {安装较慢是因为有墙,查看ruby镜像列表:$ gem ...
- jQuery实现页面元素智能定位
实现过程 Js侦听滚动事件,当页面滚动的距离(页面滚动的高度)超出了对象(要滚动的层)距离页面顶部的高度,即要滚动的层到达了浏览器窗口上边缘时,立即将对象定位属性position值改成fixed(固定 ...
- Problem 1183 - 排列
#include<iostream> #include<vector> #include<algorithm> using namespace std; int c ...
- Linux redhat
挂载U盘 fdisk -l 可以列出所有的分区,包括没有挂上的分区和usb设备.我一般用这个来查找需要挂载的分区的位置,比如挂上u盘. mount /dev/sdb1 usb/