簡體   English   中英

如何在 Hibernate 中使用 JPA Criteria API 擺脫 N+1

[英]How to get rid of N+1 with JPA Criteria API in Hibernate

我正在將我們的 DAO 從使用 Hibernate Criteria API 遷移到 JPA Criteria API。 我有一堂課, @ManyToOne有幾個@ManyToOne

@Entity
@Table(name = "A_TABLE", schema="SCHEMA_NAME")
public class A {
    @ManyToOne
    @JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '1' OR B.B_CODE = '2') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
    private B b1;
    @ManyToOne
    @JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '3' OR B.B_CODE = '4') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
    private B b2;
    ...
}

@Entity
@Table(name = "B_TABLE", schema="SCHEMA_NAME")
public class B {

}

在查詢中,我使用JoinType.LEFT以擺脫默認生成的CROSS JOIN

if (LEFT_OUTER_JOIN_ENTITIES.contains(field)) {
    path = ((From) path).join(field, JoinType.LEFT);
} else {
    path = path.get(field);
}

我得到了正確的結果,所有AB記錄都被正確檢索。 但是,在遷移之后,我遇到了 n+1 問題:盡管在生成的查詢中使用了LEFT OUTER JOIN但所有B記錄都被一一檢索。 以前(當使用 Hibernate Criteria API 時)Hibernate 能夠滿足查詢,而無需 n+1 在生成的 SQL 中具有相同的連接。

感謝您的任何想法和幫助!

更新作為使用上面的if-else搜索“b1.fieldName”的示例,我將得到以下結果:

criteriaBuilder.equal(root.join("b1", JoinType.LEFT).get("someFiled"), 42)

N+1 問題來自@ManyToOne關聯的默認FetchType.EAGER獲取策略。

因此,您需要切換到FetchType.LAZY ,如下所示:

@ManyToOne(fetch = FetchType.LAZY)
@JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '1' OR B.B_CODE = '2') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
private B b1;

@ManyToOne(fetch = FetchType.LAZY)
@JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '3' OR B.B_CODE = '4') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
private B b2;

如果您想自動檢測可能影響應用程序其他部分的 N+1 問題,那么您可以使用datasource-proxy

如果您需要使用 Criteria API 急切地獲取關聯,那么您應該使用fetch而不是join

if (LEFT_OUTER_JOIN_ENTITIES.contains(field)) {
    path = ((From) path).fetch(field, JoinType.LEFT);
} else {
    path = path.get(field);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM