Java JPA&;Hibernate:执行后续查询以获取所有数据,而不是只在一个查询中执行
我有以下疑问。我想知道为什么在使用JPA和Hibernate时,在manytone或OneToMany关系中执行急切加载时,它调用DB以获取实体信息,但另外,还会生成后续查询以获取每个子级 另一方面,当使用带有JOIN-FETCH的查询时,它会像我期望的那样执行查询,一次获取所有信息,因为fetchType表示为“EAGER” 这里是一个简单的例子: 我有一个班上的学生,他和班上的教室有着千丝万缕的联系Java JPA&;Hibernate:执行后续查询以获取所有数据,而不是只在一个查询中执行,java,hibernate,jpa,eager-loading,Java,Hibernate,Jpa,Eager Loading,我有以下疑问。我想知道为什么在使用JPA和Hibernate时,在manytone或OneToMany关系中执行急切加载时,它调用DB以获取实体信息,但另外,还会生成后续查询以获取每个子级 另一方面,当使用带有JOIN-FETCH的查询时,它会像我期望的那样执行查询,一次获取所有信息,因为fetchType表示为“EAGER” 这里是一个简单的例子: 我有一个班上的学生,他和班上的教室有着千丝万缕的联系 @Entity @Table(name = "STUDENT") public class
@Entity
@Table(name = "STUDENT")
public class Student {
@ManyToOne(optional = true, fetch = FetchType.EAGER)
@JoinColumn(name = "ClassroomID")
private Classroom mainClass;
另一边是名为教室的班级,如下所示:
@Entity
public class Classroom {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "mainClass", fetch = FetchType.EAGER)
private List<Student> studentsList;
然后它执行下一个查询的次数与分配给每个教室的学生的次数相同
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=?
问题是:为什么不一次获取所有信息?为什么它不在一个查询中获取信息?因为它已经在那里执行Join子句了
为什么只在查询中显式添加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
默认情况下,fetchtype是lazy,这意味着如果您不在请求中请求列表,Hibernate将不会收集它 在第一个请求中,您请求教室r的所有属性,包括学生列表,以便Hibernate将惰性地加载它们(在发现您需要它们之后)
但是,当fetchtype设置为“急切休眠”时,即使您不请求,也可以将其收集。由于您有一个从
课堂
到学生
的OneToMany
关系,使用单个查询将导致每行重复课堂
字段。
现在假设你有第二个OneToMany
关系,从教室
到,比如说课程
;如果对于给定的教室
您有N个学生
s和M个课程
s,您将有一个查询返回N+M行,每个行都包含我在
在“急切获取不一致”下:
JPQL和Criteria查询都默认为select fetching,因此为每个单独的关联发出二次select。关联的数量越大,额外的个人选择越多,对应用程序性能的影响就越大
另外,请注意,Hibernate为HQL查询类似地忽略了获取注释:
Hibernate忽略我的外部join=“true”或fetch=“join”设置,并使用n+1选项惰性地获取关联强>
HQL查询始终忽略映射元数据中定义的外部联接或fetch=“join”的设置。此设置仅适用于使用get()或load()获取的关联、条件查询和图形导航。如果需要为HQL查询启用即时抓取,请使用显式左连接抓取
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