Spring Boot中@ManyToMany关联抛出StackOverflowError的解决方法
解决JPA多对多关联导致StackOverflowError的方案
你的代码已经通过@JoinTable和mappedBy完成了多对多双向关联的基础配置,但出现栈溢出的核心原因是双向关联引发的循环引用——无论是JSON序列化时的递归遍历,还是自动生成的toString/equals/hashCode方法对关联集合的调用,都会导致无限递归直至栈内存耗尽。
以下是具体修复方案:
1. 处理JSON序列化循环引用
可以通过Jackson注解明确双向关联的主从关系,或直接忽略其中一方的关联字段:
方案A:使用@JsonManagedReference和@JsonBackReference
这组注解可指定序列化的主从方,从根源避免循环:
public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; String userName; String password; @ManyToMany @JoinTable( name = "student_courses", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "course_id", referencedColumnName = "id") ) @JsonManagedReference // 标记为主关联方,序列化时正常输出 List<Course> courses; // 重写toString/equals/hashCode,仅使用自身基本属性 @Override public String toString() { return "Student{" + "id=" + id + ", userName='" + userName + '\'' + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return Objects.equals(id, student.id) && Objects.equals(userName, student.userName); } @Override public int hashCode() { return Objects.hash(id, userName); } }
public class Course { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; String courseName; @ManyToMany(mappedBy = "courses") @JsonBackReference // 标记为从关联方,序列化时自动忽略 List<Student> students; // 重写toString/equals/hashCode,仅使用自身基本属性 @Override public String toString() { return "Course{" + "id=" + id + ", courseName='" + courseName + '\'' + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Course course = (Course) o; return Objects.equals(id, course.id) && Objects.equals(courseName, course.courseName); } @Override public int hashCode() { return Objects.hash(id, courseName); } }
方案B:直接在从方添加@JsonIgnore
如果不需要序列化从方的关联集合,可直接在Course的students字段上添加@JsonIgnore,切断序列化循环:
public class Course { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; String courseName; @ManyToMany(mappedBy = "courses") @JsonIgnore // 序列化时忽略该集合,避免循环 List<Student> students; // 同样需要重写toString/equals/hashCode方法 }
2. 避免方法递归调用
多数IDE自动生成的toString/equals/hashCode方法会包含关联集合对象,这会导致调用时无限递归(比如Course.toString()调用Student.toString(),而Student.toString()又调用Course.toString())。因此必须重写这些方法,仅使用实体自身的基本属性(如ID、名称),不要包含关联的集合字段。
内容的提问来源于stack exchange,提问作者dcll
相关产品推荐
相关产品推荐

