Spring Boot 多对多关联自定义中间实体查询JSON重复问题
问题产生原因
你的三个实体类均配置了双向关联关系:Employee和Course实体都持有EmployeeCourse集合属性,而EmployeeCourse实体又分别持有Employee和Course的对象引用,形成了引用循环链。
Spring MVC默认使用Jackson框架做JSON序列化时,会递归遍历对象所有属性调用getter方法,碰到循环引用就会无限嵌套序列化,最终输出你看到的重复省略内容,严重时还会直接抛出栈溢出异常。
解决方法
1. 先修复JSON无限循环问题
可以任选以下一种方案实现:
- 在关联属性上添加
@JsonIgnore注解:直接在不需要序列化的反向关联属性上加注解,序列化时会跳过该字段。示例:
// 在EmployeeCourse类的employee属性上加注解 @JsonIgnore @ManyToOne @JoinColumn(name = "employee_id") Employee employee; // 同理在course属性上也可以加@JsonIgnore
- 使用
@JsonManagedReference和@JsonBackReference配对注解:在正向关联属性上加@JsonManagedReference(会正常序列化),反向关联属性上加@JsonBackReference(序列化时会被忽略),避免循环。 - 给实体类添加
@JsonIdentityInfo注解:序列化过的实体后续会用ID值代替完整对象,避免重复序列化。示例:
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @Entity public class Employee { // 原有代码 }
2. 正确查询员工及其对应课程数量
你直接调用employeeRepo.findAll()会查询所有关联的EmployeeCourse全量数据,你只需要课程统计数量的话,更推荐使用DTO投影的方式查询,性能更高也不会返回冗余数据:
- 首先定义只承载返回结果的DTO类:
public class EmployeeCourseCountDTO { private Integer employeeId; private String firstName; private String lastName; // 存储课程数量 private Long courseCount; // 注意要写和JPQL查询字段顺序对应的全参构造方法 public EmployeeCourseCountDTO(Integer employeeId, String firstName, String lastName, Long courseCount) { this.employeeId = employeeId; this.firstName = firstName; this.lastName = lastName; this.courseCount = courseCount; } // 自行补充getter、setter方法 }
- 在
EmployeeRepository中添加自定义查询方法:
@Repository public interface EmployeeRepository extends JpaRepository<Employee, Integer> { @Query("SELECT new 你的DTO类完整路径.EmployeeCourseCountDTO(e.id, e.firstName, e.lastName, COUNT(ec.id)) " + "FROM Employee e LEFT JOIN e.employeeCourses ec GROUP BY e.id, e.firstName, e.lastName") List<EmployeeCourseCountDTO> findAllEmployeeWithCourseCount(); }
- Controller层直接调用上述方法返回即可,不会出现循环嵌套问题,也能直接拿到你需要的统计结果。
内容的提问来源于stack exchange,提问作者n3x
相关产品推荐
相关产品推荐

