在使用注解`@OneToOne`、`@OneToMany`/`@ManyToOne`、`@ManyToMany`进行双向多表查询时需要注意下面两个问题。
[TOC]
# 1. 死循环问题
![](https://img.kancloud.cn/c5/a1/c5a1170fa01181c2265daa57d47ceefd_1533x472.jpg)
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;
}
```
传递到前端得到如下类似数据,是无限的。
![](https://img.kancloud.cn/3d/da/3ddaf0f57196a625fec718aeba8605fa_1528x247.jpg)
后端将会抛出如下异常:
```
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多表查询
- 只查询指定字段
- 级联操作
- 加载规则