7)
该属性用于设置left
要理解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
加载策略:直接使用一条left
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方
可以看到,使用fetch=”join”就可以缓解N+1问题,减少SQL。理解到这个,就可以理解到out-join属性。在many-to-one上还有一个outer-join属性,outer-join的取值可以为auto,false,true,默认值为auto(可以想象为false),即不使用LEFT
理解到outer-join的好处之后,问题接着就来了,我们可以看到,假如在Employee方的dept设置为outer-join为true,那么在得到Employee的时候,就会立刻使用LEFT
<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
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
那么就只会使用一条LEFT
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的。这点需要非常注意。