賞金將在 5 天后到期。此問題的答案有資格獲得 50聲望賞金。 G. Ciardini想提請更多關注這個問題:
我正在尋找另一個答案,@NotFound 不能被接受,因為它會改變 FetchType.EAGER 中的獲取行為(因此它會減慢一切)。
我的情況
我有兩個物體,student其school結構如下:
@Table(name = "Student")
public class Student
{
@Id
@Column(name = "id")
private String id;
@Column(name = "name")
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "school")
private School school
}
@Table(name = "School")
public class School
{
@Id
@Column(name = "id")
private String id;
@Column(name = "state")
private String state;
}
以下是兩個視圖值:
學生
| ID | 姓名 | 學校 |
|---|---|---|
| 一個 | 阿爾伯特 | MCD |
| 乙 | 凱文 | 路易斯安那州立大學 |
| C | 杰克 | 紐約 |
| D | 羅伯特 | 加州 |
| 乙 | 塞繆爾 |
學校
| ID | 姓名 |
|---|---|
| MCD | 密歇根州 |
| 路易斯安那州立大學 | 洛斯 |
| 加州 | 車 |
所以當我在休眠時做一個簡單的select * from Student,它會拋出一個錯誤,因為學校表中不存在“NY”id。
(準確地說,它拋出org.hibernate.LazyInitializationException: No row with the given identifier exists)
最終目標
我的目標是繞過拋出的錯誤仍然回傳正確的物體(所以 Albert,Kevin,Robert,Samuel)
uj5u.com熱心網友回復:
您需要在課堂@NotFound(action = NotFoundAction.IGNORE)上添加學校。Student正如 Davide d'Alto 在他的回答中提到的那樣NY,表中沒有,School因此默認情況下會出現例外。
修復資料庫應該是正確的答案,但有時這是不可能的,或者可能會對其他應用程式產生其他不良后果。
在這種情況下,使用該值進行注釋時@NotFound(action = NotFoundAction.IGNORE)將設定為null以防萬一。
@Table(name = "Student")
public class Student
{
@Id
@Column(name = "id")
private String id;
@Column(name = "name")
private String name;
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "school")
private School school
}
更多資訊:
Baeldung - Hibernate EntityNotFoundException
JavaDoc
uj5u.com熱心網友回復:
您說您使用的是簡單SELECT * FROM Student查詢,這意味著您使用的是自定義查詢。
在您的情況下,您應該能夠將其更改為SELECT * FROM Student St LEFT JOIN School Sc ON Sc.ID = St.School;.
應該做的是在一個查詢中加載所有記錄,并且任何沒有匹配學校的學生記錄都應該為該類的School屬性回傳 null。Student
旁注:在使用關系和 JPA 時,如果它是這樣的簡單關系,您可以使用連接來確保在一個查詢中加載所有內容,而不是 JPA 加載所有父物體,然后為每個父物體發出查詢以獲取子物體,因此它可以有相當大的性能提升。
uj5u.com熱心網友回復:
解決方案 1:在 getter 中處理例外
可以使用的一種方法是使用靜態方法修改您的 getter 方法:Hibernate.isInitialized和Hibernate.initialize并處理EntityNotFoundException
public School getSchool() {
if (!Hibernate.isInitialized(school)) {
try {
Hibernate.initialize(school);
} catch (EntityNotFoundException ex) {
school = null;
}
}
return school;
}
@Table(name = "Student")
@Entity
public class Student
{
@Id
@Column(name = "id")
private String id;
@Column(name = "name")
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "school")
private School school;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public School getSchool() {
if (!Hibernate.isInitialized(school)) {
try {
Hibernate.initialize(school);
} catch (EntityNotFoundException ex) {
school = null;
}
}
return school;
}
public void setSchool(School school) {
this.school = school;
}
}
解決方案 2:通過單獨的存盤庫加載子物體
從您的物體中洗掉ManyToOne關系
@Table(name = "Student")
@Entity
public class Student
{
@Id
@Column(name = "id")
private String id;
@Column(name = "name")
private String name;
@Column(name = "school")
private String school;
}
為物體創建單獨的存盤庫School,可選擇按 ID 加載
@Repository
public interface SchoolRepository extends JpaRepository<School, String> {
Optional<School> findById(String id);
}
使用SchoolRepository存盤庫在所需位置加載物體
List<Student> students = studentRepository.findStudents();
Student student = students.get(2);
if (student.getSchool() != null) {
School school = schoolRepository.findById(student.getSchool()).orElse(null);
}
解決方案 3:@NotFound(action = NotFoundAction.IGNORE)和LEFT JOIN FETCH
定義忽略@NotFound注釋
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "school")
private School school
重寫您的查詢以加載Student物體。使用LEFT JOIN FETCH,它允許使用單個選擇來初始化值的關聯或集合及其父物件。它顯著提高了性能。Student物體School將由一個查詢初始化。
@Repository
public interface StudentRepository extends JpaRepository<Student, String> {
@Query(value = "select s from Student s LEFT JOIN FETCH s.school sc")
List<Student> findStudents();
}
該解決方案的主要思想是您不會有很多 EGEAR 查詢來初始化子物體,而只有一個并且@NotFound會跳過例外。
Hibernate 將生成一批查詢:
select
student0_.id as id1_34_0_,
school1_.id as id1_31_1_,
student0_.name as name2_34_0_,
student0_.school as school3_34_0_,
school1_.state as state2_31_1_
from
student student0_
left outer join
school school1_
on student0_.school=school1_.id
第二個查詢僅針對一個丟失的School物體,以確保它不存在于資料庫中
select
school0_.id as id1_31_0_,
school0_.state as state2_31_0_
from
school school0_
where
school0_.id=?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/494641.html
