Dav*_*tel 7 java hibernate jpa eager-loading
我有以下疑问。我想知道为什么在使用 JPA 和 Hibernate 时,在ManyToOne或OneToMany关系中执行预加载时,它会调用数据库以获取实体信息,但另外还会生成后续查询来获取每个子项。
另一方面,当使用带有 JOIN FETCH 的查询时,它会按照我的预期执行查询,一次获取所有信息,因为 fetchType 表示为“EAGER”。
这是一个简单的例子:
我有一个班级学生,它与班级教室有多对一的关系。
@Entity
@Table(name = "STUDENT")
public class Student {
@ManyToOne(optional = true, fetch = FetchType.EAGER)
@JoinColumn(name = "ClassroomID")
private Classroom mainClass;
Run Code Online (Sandbox Code Playgroud)
另一边有一个名为 Classroom 的类,如下:
@Entity
public class Classroom {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "mainClass", fetch = FetchType.EAGER)
private List<Student> studentsList;
Run Code Online (Sandbox Code Playgroud)
在获取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
Run Code Online (Sandbox Code Playgroud)
然后,它执行下一个查询的次数与分配给每个教室的学生的次数相同。
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=?
Run Code Online (Sandbox Code Playgroud)
问题是:为什么不一次性获取所有信息?为什么它不在一次查询中获取信息?因为它已经在那里执行 Join 子句。
为什么在查询中显式添加Fetch时,它会执行所请求的操作?
例如:
SELECT
r
FROM
Classroom r
LEFT JOIN FETCH
r.classStudents */
Run Code Online (Sandbox Code Playgroud)
然后,输出查询确实在一个查询中获取所有信息:
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
Run Code Online (Sandbox Code Playgroud)
我发现它在https://vladmihalcea.com/eager-fetching-is-a-code-smell/\n在EAGER 获取不一致下进行了描述:
\n\n\nJPQL 和 Criteria 查询都默认选择获取,因此为每个单独的 EAGER 关联发出辅助选择。Associations\xe2\x80\x99 数字越大,额外的单独 SELECT 就越多,对我们应用程序性能的影响就越大。
\n
另请注意,Hibernate 同样会忽略 HQL 查询的获取注释:\n https://developer.jboss.org/wiki/HibernateFAQ-AdvancedProblems#jive_content_id_Hibernate_ignores_my_outerjointrue_or_fetchjoin_setting_and_fetches_an_association_lazily_using_n1_selects
\n\n\nHibernate 忽略我的 external-join="true" 或 fetch="join" 设置并使用 n+1 选择来延迟获取关联!
\nHQL 查询始终忽略映射元数据中定义的外连接或 fetch="join" 设置。此设置仅适用于使用 get() 或 load()、条件查询和图形导航获取的关联。如果需要为 HQL 查询启用急切提取,请使用显式 LEFT JOIN FETCH。
\n
归档时间: |
|
查看次数: |
7028 次 |
最近记录: |