![](/img/trans.png)
[英]Hibernate (JPA) how to do an eager query, loading all child objects
[英]JPA & Hibernate: Eager loading performing subsequent queries to fetch all data, instead of doing it in just one query
我有以下疑問。 我想知道為什么在使用 JPA 和 Hibernate 時,在ManyToOne或OneToMany關系中執行 Eager 加載時,它調用 DB 以獲取實體信息,但另外生成后續查詢以獲取每個子項。
另一方面,當使用帶有 JOIN FETCH 的查詢時,它會按照我的預期執行查詢,一次性獲取所有信息,因為 fetchType 表示為“EAGER”。
這是一個簡單的例子:
我有班級學生,它與班級教室有多對一關系。
@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;
當獲得課堂對象,它執行一個查詢,以獲得從本身和后續查詢的信息獲取包含在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=?
問題是:為什么不一次性獲取所有信息? 為什么不只在一個查詢中獲取信息? 因為它已經在那里執行 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
由於您有一個從Classroom
到Student
的OneToMany
關系,使用單個查詢會導致Classroom
字段對每一行重復。 現在假設您有第二個OneToMany
關系,從Classroom
到Course
; 如果對於給定的Classroom
您有 N 個Student
和 M 個Course
,您將有一個返回 N+M 行的查詢,每行都包含Classroom
的相同字段。
我發現它在https://vladmihalcea.com/eager-fetching-is-a-code-smell/下的EAGER fetching inconsistencies 中描述:
JPQL 和 Criteria 查詢默認選擇提取,因此為每個單獨的 EAGER 關聯發出輔助選擇。 關聯的數量越大,附加的單個 SELECTS 越多,它對我們的應用程序性能的影響就越大。
另請注意,Hibernate 同樣忽略了 HQL 查詢的提取注釋: https : //developer.jboss.org/wiki/HibernateFAQ-AdvancedProblems#jive_content_id_Hibernate_ignores_my_outerjointrue_or_fetchjoin_setting_and_fetches_an_association_lazily_using_n1_s
Hibernate 會忽略我的 outer-join="true" 或 fetch="join" 設置並使用 n+1 選擇懶惰地獲取關聯!
HQL 查詢始終忽略映射元數據中定義的外連接或 fetch="join" 設置。 此設置僅適用於使用 get() 或 load() 獲取的關聯、條件查詢和圖形導航。 如果您需要為 HQL 查詢啟用預取,請使用顯式 LEFT JOIN FETCH。
默認情況下 fetchtype 是惰性的,這意味着如果您不在請求中請求列表,Hibernate 將不會收集它。
在第一個請求中,您要求 Classroom r 的所有屬性,包括學生列表,以便 Hibernate 會延遲加載它們(在發現您需要它們之后)。
但是當 fetchtype 設置為eager hibernate 時,即使你不問它也會收集它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.