You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jackson序列化Hibernate JPA双向关联实体触发无限递归报错

问题根本原因
  1. 双向关联序列化循环:JPA双向关联规则下,Author实体持有Book集合属性,Book实体又持有对应关联的Author对象。Spring MVC默认使用Jackson做JSON序列化时,会反复递归序列化两个对象的关联属性,最终触发栈溢出。
  2. 业务逻辑错误:你写的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 00:36:05