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

Spring Boot+PostgreSQL问题:JSON递归错误与关联字段为空

解决方案

问题1:查询Medecin时Cabinet非ID字段为空

原因:@ManyToOne默认使用懒加载(FetchType.LAZY),JPA仅返回Cabinet的代理对象(仅包含ID),实际字段未从数据库加载,导致序列化后非ID字段为空。

解决方法(推荐使用EntityGraph或Fetch Join,避免EAGER带来的性能问题)

方式1:使用@EntityGraph在Repository中指定关联加载

在Medecin的Repository接口中,给查询方法添加@EntityGraph注解,明确加载关联的Cabinet:

public interface MedecinRepository extends JpaRepository<Medecin, Long> {
    @EntityGraph(attributePaths = {"cabinet"})
    Medecin findById(Long id);

    // 批量查询时也可使用
    @EntityGraph(attributePaths = {"cabinet"})
    List<Medecin> findAll();
}

方式2:使用Fetch Join的JPQL查询

通过JPQL的join fetch语法强制加载关联对象:

public interface MedecinRepository extends JpaRepository<Medecin, Long> {
    @Query("SELECT m FROM Medecin m JOIN FETCH m.cabinet WHERE m.id = :id")
    Medecin findByIdWithCabinet(@Param("id") Long id);
}

方式3:修改fetch类型为EAGER(不推荐,可能导致性能损耗)

直接修改@ManyToOne的fetch属性,但会导致每次查询Medecin都强制加载Cabinet,仅适合关联数据必用的场景:

@ManyToOne(fetch = FetchType.EAGER)
private Cabinet cabinet;

问题2:查询Cabinet时出现无限递归(StackOverflowError)

原因:Cabinet包含Medecin列表,Medecin又引用Cabinet,Jackson序列化时会循环遍历两者的关联关系,导致栈溢出。

解决方法:使用Jackson的双向引用注解

通过@JsonManagedReference和@JsonBackReference标记双向关联的父子关系,告诉Jackson序列化时忽略反向引用:

修改Medecin类

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Medecin extends User {
    private int inp;
    private String specialite;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JsonBackReference // 标记为反向引用,序列化时忽略
    private Cabinet cabinet;
}

修改Cabinet类

@Entity(name = "Cabinet")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cabinet {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "cabinet_id")
    private Long id;
    private String denomination;
    private String adresse;
    private int telephone;
    private double longitude;
    private double latitude;
    
    @OneToMany(mappedBy = "cabinet", cascade = CascadeType.ALL)
    @JsonManagedReference // 标记为正向引用,正常序列化
    private List<Medecin> medecins = new ArrayList<>();
}

其他可选方案

  • 使用@JsonIgnore:在其中一方的关联字段添加该注解,直接忽略该字段的序列化(但会丢失关联数据,仅适合不需要返回该字段的场景)。
  • 使用@JsonIdentityInfo:给实体类添加该注解,通过ID标识对象,避免重复序列化(适合复杂关联场景):
    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
    @Entity
    public class Cabinet { ... }
    
    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
    @Entity
    public class Medecin extends User { ... }
    

内容的提问来源于stack exchange,提问作者Anas Hafidi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 12:58:10