JPA Hibernate双向一对多关联查询触发无限循环问题如何解决
JPA双向关联查询无限循环问题解决方案
问题原因
该问题是双向关联的实体在JSON序列化阶段触发了无限递归:TiposDocumentosIdentidad 包含 Personas 集合属性,每个 Personas 又关联回 TiposDocumentosIdentidad 类型的属性,Jackson序列化时会反复遍历两个对象的关联字段,最终导致无限嵌套的返回结果。你添加的@XmlTransient是JAXB用于XML序列化的注解,对Spring Boot默认使用的Jackson JSON序列化不生效,因此无法解决问题。
解决方案
可根据业务需求从以下4种常用方案中选择:
方案1:使用@JsonIgnore忽略关联字段(实现最简单)
在不需要序列化的关联字段上加Jackson提供的@JsonIgnore注解,让序列化阶段直接跳过该字段即可:
// 修改TiposDocumentosIdentidad类的getPersonasCollection方法 @JsonIgnore @XmlTransient public Collection<Personas> getPersonasCollection() { return personasCollection; }
如果业务不需要在查询证件类型时返回关联的人员列表,选该方案最快。
方案2:使用@JsonManagedReference+@JsonBackReference配对处理双向关联
如果需要保留单侧关联的序列化能力,用这组注解配对即可:
- 父实体(关联的被持有方)的集合字段加
@JsonManagedReference,表示该字段会被正常序列化 - 子实体(关联的持有方)的关联字段加
@JsonBackReference,表示序列化时忽略该字段,避免循环
示例代码:
// TiposDocumentosIdentidad类 @JsonManagedReference @OneToMany(cascade = CascadeType.ALL, mappedBy = "tidoId") private Collection<Personas> personasCollection;
// Personas类 @JsonBackReference @JoinColumn(name = "TIDO_ID", referencedColumnName = "TIDO_ID") @ManyToOne(optional = false) private TiposDocumentosIdentidad tidoId;
注解位置可根据业务需求调整,如果需要查询人员时返回关联的证件类型信息,就把@JsonBackReference加在personasCollection字段上,@JsonManagedReference加在tidoId字段上即可。
方案3:使用@JsonIdentityInfo保留双向关联的序列化
如果需要两侧都展示关联信息,给两个实体类都加上@JsonIdentityInfo注解,序列化时遇到已经序列化过的对象,只会输出ID而不会重复嵌套:
// TiposDocumentosIdentidad类上加注解 @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "tidoId") @Entity @Table(name = "TIPOS_DOCUMENTOS_IDENTIDAD") @XmlRootElement public class TiposDocumentosIdentidad implements Serializable { // 原有代码不变 }
// Personas类上加注解 @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "persId") @Entity @Table(name = "PERSONAS") @XmlRootElement public class Personas implements Serializable { // 原有代码不变 }
方案4:使用DTO传输对象(生产级最规范方案)
不要直接把JPA实体返回给接口层,定义专门的DTO类接收查询结果,按需赋值字段,从根源避免关联字段暴露导致的循环问题,同时也可以避免实体内部敏感字段泄露到对外接口。
内容的提问来源于stack exchange,提问作者Diego Izquierdo Dussan
相关产品推荐
相关产品推荐

