SpringBoot获取Book实体时出现StackOverflowError求助
解决Spring双向多对多关联导致的StackOverflowError问题
问题原因
你遇到的StackOverflowError是双向多对多关联的循环序列化导致的:
BookEntity中包含List<Author>,Author中又包含List<BookEntity>,形成双向引用。- 当Spring的JSON转换器(如Jackson)序列化接口返回的
BookEntity列表时,会递归遍历Book→Author→Book→Author...,不断调用双方的getter方法,最终耗尽栈内存引发溢出。 - 另外你的双向多对多关联未指定
mappedBy,JPA会自动生成两张中间表,这也是需要修正的潜在问题。
解决方案
方案1:用@JsonIgnore忽略一方的关联属性
在其中一方的关联字段上添加@JsonIgnore注解,阻止JSON序列化该字段,打断循环链。
比如修改Author类:
@Entity public class Author { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String name; @ManyToMany @JsonIgnore // 忽略该字段的序列化 private List<BookEntity> book; // 构造方法、getter、setter 保持不变 }
方案2:用@JsonManagedReference和@JsonBackReference(推荐)
通过这对注解区分双向关联的“管理端”和“反向端”,管理端会被正常序列化,反向端则被忽略,既保留业务数据又避免循环。
同时补充mappedBy指定关联维护方,避免生成冗余中间表:
// BookEntity类(管理端) @Entity public class BookEntity { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String title; @ManyToMany @JsonManagedReference // 标记为管理端,正常序列化 private List<Author> author; // 构造方法、getter、setter 保持不变 }
// Author类(反向端) @Entity public class Author { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String name; @ManyToMany(mappedBy = "author") // 指定由BookEntity的author字段维护关联 @JsonBackReference // 标记为反向端,序列化时忽略 private List<BookEntity> book; // 构造方法、getter、setter 保持不变 }
方案3:使用DTO(数据传输对象)
创建与实体类分离的DTO对象,只封装接口需要返回的字段,通过实体转DTO的方式彻底避免循环引用,同时解耦数据库实体和接口返回结构。
示例:
// BookDTO.java public class BookDTO { private long id; private String title; private List<AuthorDTO> authors; // 构造方法、getter、setter public BookDTO(long id, String title, List<AuthorDTO> authors) { this.id = id; this.title = title; this.authors = authors; } }
// AuthorDTO.java public class AuthorDTO { private long id; private String name; // 构造方法、getter、setter public AuthorDTO(long id, String name) { this.id = id; this.name = name; } }
修改Controller中的方法:
@GetMapping List<BookDTO> getAllBooks() { return bookRepository.findAll().stream() .map(book -> new BookDTO( book.getId(), book.getTitle(), book.getAuthor().stream() .map(author -> new AuthorDTO(author.getId(), author.getName())) .toList() )).toList(); }
内容的提问来源于stack exchange,提问作者user21180921
相关产品推荐
相关产品推荐

