Spring Boot3+Hibernate6.5实体双向关联栈溢出问题排查
Spring Boot3(Hibernate6)中Spot与SpotCondition双向关联引发的栈溢出及代理转换异常问题
数据库中Spot和SpotCondition存在双重关联:
- Spot作为多个SpotCondition的父级,是基础OneToMany关联;
- 每个Spot通过外键
spt_current_condition关联当前的SpotCondition,需实现双向关联。
该逻辑在Spring Boot2.7.1(Hibernate5)中运行正常,但迁移至Spring Boot3(Hibernate6.5)后,查询包含内嵌CurrentSpotCondition的Spot时出现java.lang.StackOverflowError,推测是循环关联导致。
实体类代码
Spot类
@Entity @Table( name = "t_spot_spt" ) @Data @NoArgsConstructor public class Spot { @Id @GeneratedValue( strategy = GenerationType.IDENTITY ) @Column( name = "spt_id" ) private Integer id; @OneToOne( fetch = FetchType.EAGER ) @JoinColumn( name = "spt_current_condition" ) private SpotCondition currentCondition; @OneToMany( mappedBy = "spot", fetch = FetchType.LAZY ) private List<SpotCondition> conditions; @Column( name = "spt_bla_id" ) private Integer bladeId; }
SpotCondition抽象类
@Entity @Table( name = "t_spot_condition_scd" ) @Data @NoArgsConstructor @ToString( onlyExplicitlyIncluded = true ) public abstract class SpotCondition implements Diffable<SpotCondition> { @Id @GeneratedValue( strategy = GenerationType.IDENTITY ) @Column( name = "scd_id" ) @ToString.Include protected Integer id; @ManyToOne( fetch = FetchType.EAGER ) @JoinColumn( name = "scd_spt_id" ) protected Spot spot; }
Repository与Service代码
SpotRepository
public interface SpotRepository extends JpaRepository<Spot, Integer> { List<Spot> findByBladeId( Integer bladeId ); }
Service核心方法
@Override @Transactional( readOnly = true ) public Integer findWorstDamageSeverityIdByBlade( Integer bladeId ) { short level = Short.MIN_VALUE; Integer sevId = null; boolean repairPresent = false; for ( Spot spt : spotRepository.findByBladeId( bladeId ) ) { SpotCondition sc = spt.getCurrentCondition(); // 执行相关操作 ... } }
报错信息
初始栈溢出错误
2024-07-25T21:09:55.332+02:00[0;39m [31mERROR[0;39m [35m19556[0;39m [2m---[0;39m [2m[p-nio-80-exec-6][0;39m [2m[0;39m[36mo.a.c.c.C.[.[.[.[dispatcherServlet] [0;39m [2m:[0;39m Servlet.service() for servlet [dispatcherServlet] in context with path [/bladeexpert] threw exception [Handler dispatch failed: java.lang.StackOverflowError] with root cause java.lang.StackOverflowError: null at org.hibernate.sql.results.internal.NavigablePathMapToInitializer.get(NavigablePathMapToInitializer.java:33) ~[hibernate-core-6.5.2.Final.jar:6.5.2.Final] ...(省略部分栈信息)
修改为LAZY后的警告
2024-07-25T21:30:11.878+02:00[0;39m [33m WARN[0;39m [35m19556[0;39m [2m---[0;39m [2m[p-nio-80-exec-3][0;39m [2m[0;39m[36mo.h.e.i.StatefulPersistenceContext [0;39m [2m:[0;39m HHH000179: Narrowing proxy to class com.bladeexpert.core.entity.spot.damage.OutdoorDamageSpotCondition - this operation breaks ==
修改后栈溢出问题解决,但无法获取CurrentSpotCondition。
已尝试的操作
将Spot类中currentCondition的@OneToOne获取策略从EAGER改为LAZY,栈溢出问题消失,但出现代理转换警告且无法获取到CurrentSpotCondition。
恳请提供解决思路,感谢帮助!
内容的提问来源于stack exchange,提问作者Colin Lefebvre
相关产品推荐
相关产品推荐

