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

升级Hibernate 6.6.4.Final后查询陷入无限循环问题求助

Spring Boot 3 + Hibernate 6 查询无限循环问题解决

问题场景

应用在 Spring Boot 2.5.14 + Hibernate 5.6.10.Final 环境下运行正常,升级至 Spring Boot 3.2.3 + Hibernate 6.6.4.Final 后出现查询无限循环问题。涉及实体类为 FooEntity、BarEntity(使用包含 FooEntity 引用的复合主键),尝试过 @JsonIgnoreProperties、@JsonBackReference/@JsonManagedReference 注解均无效,且所有 Hibernate 6.x 版本都存在该问题。

问题根源

Hibernate 6 对懒加载代理的处理逻辑有调整,再加上 Lombok @Data 注解自动生成的 toString()、equals()、hashCode() 方法会触发懒加载关联对象的初始化,进而形成循环引用链:
FooEntity.toString() → 调用 BarEntity.toString() → 调用 BarEntityKey.toString() → 调用 FooEntity.toString(),最终导致无限循环。

之前的 Jackson 序列化注解无效,是因为循环并非发生在 JSON 序列化阶段,而是在实体加载后调用 Lombok 生成的方法时就触发了。

解决方案

方案1:调整 Lombok 注解,避免触发关联加载

给循环引用的字段添加 Lombok 排除注解,阻止 toString()、equals()、hashCode() 方法包含这些关联对象:

修改后的 FooEntity:

@Entity
@Table(name = "FOO_TABLE")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
public class FooEntity implements Serializable {

    // other properties

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "key.foo", cascade = CascadeType.ALL, orphanRemoval = true)
    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    private final Set<BarEntity> barEntities = new HashSet<>();
    
    // other properties

}

修改后的 BarEntityKey:

@Embeddable
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BarEntityKey implements Serializable {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "FOO_UID")
    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    private FooEntity foo;
    
    // other properties
    
}

方案2:优化关联映射,避免主键包含实体引用

将复合主键中的实体引用改为ID字段,通过 @MapsId 关联实体,从根源减少循环触发的可能:

  1. 修改 BarEntityKey,用ID字段替代实体引用:
@Embeddable
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BarEntityKey implements Serializable {

    private Long fooUid;
    
    // other properties
    
}
  1. 修改 BarEntity,添加实体关联并绑定主键字段:
@Entity
@Table(name = "BAR_TABLE")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = false)
public class BarEntity implements Serializable {
    
    @EmbeddedId
    private BarEntityKey key;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("fooUid")
    @JoinColumn(name = "FOO_UID")
    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    private FooEntity foo;
    
    // other properties
}
  1. 修改 FooEntity 的关联映射:
@Entity
@Table(name = "FOO_TABLE")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
public class FooEntity implements Serializable {

    // other properties

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "foo", cascade = CascadeType.ALL, orphanRemoval = true)
    @ToString.Exclude
    @EqualsAndHashCode.Exclude
    private final Set<BarEntity> barEntities = new HashSet<>();
    
    // other properties

}

方案3:检查并调整Hibernate懒加载配置

确保 spring.jpa.open-in-view 配置为 false(Spring Boot 3 默认值),避免视图层或其他非业务逻辑阶段意外触发懒加载,加重循环引用风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 18:15:28