升级Hibernate 6.6.4.Final后查询陷入无限循环问题求助
问题场景
应用在 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 关联实体,从根源减少循环触发的可能:
- 修改
BarEntityKey,用ID字段替代实体引用:
@Embeddable @Data @NoArgsConstructor @AllArgsConstructor @Builder public class BarEntityKey implements Serializable { private Long fooUid; // other properties }
- 修改
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 }
- 修改
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

