在使用注解`@OneToOne`、`@OneToMany`/`@ManyToOne`、`@ManyToMany`進行雙向多表查詢時需要注意下面兩個問題。
[TOC]
# 1. 死循環問題

lombok 框架中提供的注解`@Data`、`@ToString`、`@EqualsAndHashCode`,會用到當前類的所有變量來重寫對應的方法,在調用這些方法時就可能進入死循環,比如`toString`方法。
<br/>
在`Trainee`中調用`Teacher`,`Teacher`又調用了`Trainee`就會形成一個死循環,這樣在進行查詢時就會拋出如下異常,導致查詢失敗。
```java
java.lang.StackOverflowError
at java.base/java.lang.StringUTF16.checkBoundsOffCount(StringUTF16.java:1482)
```
解決辦法如下:
**1. 不調用`toString`、`equals`、`hashCode`方法**
**2. 重寫`toString`、`equals`、`hashCode`方法**
自己重寫`toString`、`equals`、`hashCode`方法,讓這些方法不要調用全部的變量。
```java
public class Trainee {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Trainee trainee = (Trainee) o;
return id.equals(trainee.id) &&
name.equals(trainee.name) &&
age.equals(trainee.age) &&
gender.equals(trainee.gender) &&
//1. 不要直接調用整個 teacher
teacher.equals(trainee.teacher.getId());
}
@Override
public int hashCode() {
//這樣直接調用teacher來重寫hashCode方法,當調用到hashCode方法時就會死循環了
//return Objects.hash(id, name, age, gender, teacher);
//要么不使用 teacher 來重寫hashCode方法,要么不要直接使用 teacher
//return Objects.hash(id, name, age, gender);
return Objects.hash(id, name, age, gender, teacher.getId());
}
@Override
public String toString() {
return "Trainee{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
//直接調用整個 teacher重寫 toString方法,當調用到該方法時就會死循環了
//", teacher=" + teacher +
//要么不使用 teacher 來重寫toString方法,要么不要直接使用 teacher
", teacher=" + teacher.getId() +
'}';
}
}
```
<br/>
# 2. 后端數據傳遞到前端
如下兩個實體類互相引用,則數據傳遞到前端時也會造成死循環。
```java
public class Trainee {
//Trainee中引用Teacher
private Teacher teacher;
}
public class Teacher {
//Teacher中引用Trainee
private List<Trainee> traineeList;
}
```
傳遞到前端得到如下類似數據,是無限的。

后端將會拋出如下異常:
```
java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
```
<br/>
解決辦法如下:
**1. 添加注解`@JsonIgnoreProperties`來忽略屬性**
(1)引入如下依賴。
```xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.12.5</version>
</dependency>
```
(2)標注注解`@JsonIgnoreProperties`,忽略屬性。
```java
public class Trainee {
//忽略 Teacher.traineeList 屬性
@JsonIgnoreProperties(value = {"traineeList"})
private Teacher teacher;
}
public class Teacher {
//忽略 Trainee.teacher 屬性
@JsonIgnoreProperties(value = {"teacher"})
private List<Trainee> traineeList;
}
```
- MapStruct屬性映射
- MapStruct是什么
- maven依賴
- 基本映射
- 字段名不一致的映射
- 字段類型不一致的映射
- 基本數據類型轉換
- 日期格式轉換
- 使用表達式轉換
- 枚舉映射
- 多個源類的映射
- 集合的映射
- 添加自定義映射方法
- 映射前后
- 添加默認值
- 映射異常處理
- SpringDataJPA
- SpringDataJPA是什么
- 與JPA、Hibernate的關系
- 環境搭建
- 簡單CURD操作
- 內部原理
- 主鍵生成策略
- 聯合主鍵
- 查詢方式
- 方法命名規則查詢
- 限制查詢結果查詢
- 注解@Query查詢
- 命名參數查詢
- SpEL表達式查詢
- 原生查詢
- 更新與刪除
- Specification動態查詢
- 核心接口
- 查詢例子
- 分頁查詢與排序
- 多表查詢
- 一對一查詢
- 一對多查詢
- 多對多查詢
- 注意事項
- Specification多表查詢
- @Query多表查詢
- 只查詢指定字段
- 級聯操作
- 加載規則