我有如下疑问。当使用JPA和Hibernate时,进行ManyToOne或OneToMany关系的Eager loading时,为什么会调用DB来获取实体信息,但同时还会产生后续查询以获取每个子元素。
另一方面,在使用JOIN FETCH查询时,它按照我的预期执行查询,并且一次性获取所有信息,因为fetchType被指定为“EAGER”。
以下是一个简单的例子:
我有一个学生类,它与教室类存在ManyToOne关系。
在另一端,有一个名为"Classroom"的类,如下所示:
在获取Classroom对象时,它会执行一个查询来获取自身的信息,以及针对每个Classroom对象所包含的studentsList中每个学生的信息进行后续查询。
第一次查询:
问题是:为什么它不一次性获取所有信息?为什么不在一个查询中获取所有信息?因为它已经执行了连接子句。
为什么只有在查询中显式添加Fetch时,它才执行要求的操作?
例如:
另一方面,在使用JOIN FETCH查询时,它按照我的预期执行查询,并且一次性获取所有信息,因为fetchType被指定为“EAGER”。
以下是一个简单的例子:
我有一个学生类,它与教室类存在ManyToOne关系。
@Entity
@Table(name = "STUDENT")
public class Student {
@ManyToOne(optional = true, fetch = FetchType.EAGER)
@JoinColumn(name = "ClassroomID")
private Classroom mainClass;
在另一端,有一个名为"Classroom"的类,如下所示:
@Entity
public class Classroom {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "mainClass", fetch = FetchType.EAGER)
private List<Student> studentsList;
在获取Classroom对象时,它会执行一个查询来获取自身的信息,以及针对每个Classroom对象所包含的studentsList中每个学生的信息进行后续查询。
第一次查询:
Hibernate:
/* SELECT
r
FROM
Classroom r
LEFT JOIN
r.classStudents */
select
classroom0_.id as id1_0_,
classroom0_.number as number2_0_
from
Classroom classroom0_
left outer join
STUDENT classstude1_
on classroom0_.id=classstude1_.ClassroomID
然后,它根据每个教室分配的学生数量执行下一个查询。
Hibernate:
/* load one-to-many com.hw.access.Classroom.classStudents */
select
classstude0_.ClassroomID as Classroo4_0_1_,
classstude0_.id as id1_1_1_,
classstude0_.id as id1_1_0_,
classstude0_.FIRST_NAME as FIRST_NA2_1_0_,
classstude0_.LAST_NAME as LAST_NAM3_1_0_,
classstude0_.ClassroomID as Classroo4_1_0_
from
STUDENT classstude0_
where
classstude0_.ClassroomID=?
问题是:为什么它不一次性获取所有信息?为什么不在一个查询中获取所有信息?因为它已经执行了连接子句。
为什么只有在查询中显式添加Fetch时,它才执行要求的操作?
例如:
SELECT
r
FROM
Classroom r
LEFT JOIN FETCH
r.classStudents */
然后,输出查询将所有信息仅使用一个查询获取:
Hibernate:
select
classroom0_.id as id1_0_0_,
classstude1_.id as id1_1_1_,
classroom0_.number as number2_0_0_,
classstude1_.FIRST_NAME as FIRST_NA2_1_1_,
classstude1_.LAST_NAME as LAST_NAM3_1_1_,
classstude1_.ClassroomID as Classroo4_1_1_,
classstude1_.ClassroomID as Classroo4_0_0__,
classstude1_.id as id1_1_0__
from
Classroom classroom0_
left outer join
STUDENT classstude1_
on classroom0_.id=classstude1_.ClassroomID