Jackson序列化Hibernate JPA双向关联实体触发无限递归报错
问题根本原因
- 双向关联序列化循环:JPA双向关联规则下,
Author实体持有Book集合属性,Book实体又持有对应关联的Author对象。Spring MVC默认使用Jackson做JSON序列化时,会反复递归序列化两个对象的关联属性,最终触发栈溢出。 - 业务逻辑错误:你写的
insertAuthor方法中手动创建了空的Book对象,还直接覆盖了前端传入的书籍集合,所以返回结果里title字段全部为null,和请求参数不匹配。
解决方案
首先解决序列化循环问题,三种常用方案可按需选择:
- 方案1:使用
@JsonManagedReference+@JsonBackReference组合(推荐,无额外性能损耗)
在Author的book属性上加@JsonManagedReference,标记为序列化主动端,会正常序列化关联的书籍集合;在Book的author属性上加@JsonBackReference,标记为序列化被动端,序列化时会自动忽略该属性,从根源切断循环。 - 方案2:使用
@JsonIgnore注解
直接在Book的author属性上加@JsonIgnore,序列化时强制跳过该字段,实现简单,但后续所有返回Book对象的接口都不会携带关联的作者信息。 - 方案3:使用
@JsonIdentityInfo注解
给Author和Book类都加上@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id"),序列化时遇到已经输出过的同ID对象,只会输出ID值,不会重复序列化完整对象,适合需要双向展示关联信息的场景。
其次要修复Service层的逻辑错误,删除手动创建空书籍集合的代码,直接处理前端传入的书籍参数即可。
修复后的代码示例
实体类(方案1举例)
public class Author { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer author_id; private String name; private String language; @JsonManagedReference @OneToMany(cascade = CascadeType.ALL, mappedBy = "author") private Set<Book> book; // getter setter } public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String title; @JsonBackReference @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "author_id") private Author author; // getter setter }
业务层
@Override public Author insertAuthor(Author author) { // 给前端传入的所有书籍设置关联的作者 if (author.getBook() != null) { author.getBook().forEach(book -> book.setAuthor(author)); } return authorRepo.save(author); }
内容的提问来源于stack exchange,提问作者Faheem azaz Bhanej
相关产品推荐
相关产品推荐

