在下面的 Hibernate 生成的查詢中,student_idandcollege_id_fk 欄位被選中了兩次,為什么會這樣,目的是什么?這個可以修嗎。
2022-02-21 07:12:33.213 TRACE 19824 --- [ main] o.h.type.descriptor.sql.BasicExtractor : extracted value ([student_1_12_0_] : [INTEGER]) - [6]
Hibernate:
select
students0_.college_id_fk as college_3_12_0_,
students0_.student_id as student_1_12_0_,
students0_.student_id as student_1_12_1_,
students0_.college_id_fk as college_3_12_1_,
students0_.student_name as student_2_12_1_
from
student students0_
where
students0_.college_id_fk=?
2022-02-21 07:12:33.214 TRACE 19824 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1]
呼叫代碼如下 -
collegeRepo.findAll().forEach( c -> System.err.println("college wit students: " c.getStudents() ) );
以上是spring data jpa提供的方法,所以有spring data jpa的實作。
我經歷了類似的問題,這些問題表明物體可能存在一些問題,例如錯誤的映射或 @Id 的錯誤使用。所以,我在這里粘貼我的物體關系。
物體關系是 - 一個學生屬于一所大學,一個大學可以有多個學生。所以 Student --> College 之間存在 ManyToOne 關系,College --> Student 之間存在 OneToMany 關系。
物體如下。
(小編輯 1 - 根據 Ken 的建議,我評論了 College.students 物體的熱切加載,但“選擇兩次”問題仍然存在。編輯結束 1)
@Entity
public class College {
@Id
@GeneratedValue
private int collegeId;
private String collegeName;
@OneToMany(targetEntity = Student.class, mappedBy = "college") //, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
//as you can see students is loaded eagerly.
private List<Student> students;
和
@Entity
public class Student {
@Id
@GeneratedValue
private int studentId;
private String studentName;
@ManyToOne
@JoinColumn(name = "collegeId_fk")
private College college;
我在搜索引擎上搜索“Hibernate 選擇同一列兩次”。但沒有有用的結果。因此,SOF 是理解或解決此問題的唯一方法。
根據@tgdavies 的要求:spring boot 版本是 2.6.1,hibernate-core 版本是 5.6.1
uj5u.com熱心網友回復:
6.0 版之前的 Hibernate 依賴于為每個列使用生成的別名。因此,如果您有多個關聯,甚至只是一個反向多關聯,您將看到重復的列選擇,因為 6.0 之前的 Hibernate 基于別名獲取值。Hibernate 6.0 切換到基于位置的提取和對同一列的重復選擇。
uj5u.com熱心網友回復:
您提到的 select SQL 是由大學學生的急切加載觸發的。我簡要跟蹤了源代碼,歸結為在此處OneToManyPersister生成選擇子句。我不知道為什么作者會為這種情況生成包含一些重復列的 select 子句,而且我認為除非您使用自己的 hibernate 修補版本,否則您無法更改此行為。
如果你真的不希望它發生,我的建議是不要對學院的學生使用 Eager fetching。畢竟,這是一個壞主意,因為 Eager fetching 會引入 N 1 查詢問題。如果你有 100 所大學,這樣的 SQL 會重復 100 次,在你加載大學之后,一一加載這 100 所大學的學生。
為了避免 N 1 查詢問題和 SQL 中的重復列,您可以撰寫一個 JPQL 查詢來獲取 join 學院及其學生:
@Query("select distinct c from College c left join fetch c.students")
List<College> findAllCollegeWithStudents();
或者@EntityGraph,如果您愿意,可以以宣告方式使用:
@EntityGraph(value = "students")
List<College> findAll();
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/432633.html
