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

JPA查询数据库触发java.lang.StackOverflowError栈溢出错误如何解决?

异常根因分析

核心是JPA双向关联实体类的hashCode/equals方法循环调用导致栈溢出,具体触发逻辑:

  1. UserDomain、UserRoleDomain、RoleDomain三者存在双向关联映射:UserDomain持有Set<UserRoleDomain>集合,UserRoleDomain同时持有UserDomain和RoleDomain的引用,RoleDomain也持有反向关联的UserRoleDomain集合。
  2. 实体类的hashCode方法(大概率是Lombok @Data自动生成,或是手动编写时未排除关联属性)计算时会递归调用关联对象的hashCode:UserRoleDomain计算哈希要调用关联的RoleDomain的哈希方法,RoleDomain计算哈希要调用持有的UserRoleDomain集合的哈希,Set计算哈希会遍历所有元素调用hashCode,形成无限循环调用,最终触发StackOverflowError。
  3. 本次调用userService.getById查询用户后,用objectMapper.convertValue将UserDomain转为UserDto时,触发了Hibernate懒加载集合的初始化,Set初始化后要计算哈希值,直接触发了循环调用逻辑。
修复方案
  • 方案1:重写关联实体的hashCode和equals方法,仅用主键/业务唯一字段生成,排除关联属性
    如果是用Lombok生成实体方法,给关联属性加上@EqualsAndHashCode.Exclude注解即可,示例:
    @Data
    @Entity
    public class RoleDomain {
        @Id
        private Long roleId;
        private String roleName;
        @OneToMany(mappedBy = "roleDomain")
        @EqualsAndHashCode.Exclude // 排除关联属性,避免循环调用
        private Set<UserRoleDomain> userRoleDomains;
    }
    
    如果是手动编写hashCode/equals,仅用实体自身的主键、业务唯一字段参与计算即可,不要引入关联对象。
  • 方案2:实体转DTO时避免触发懒加载
    将关联集合的FetchType设为LAZY后,转换DTO前手动关闭Hibernate会话,或是用MapStruct等DTO映射框架指定仅映射需要的基础字段,不映射关联的集合属性;也可以在Repository查询时直接用DTO投影返回需要的字段,避免查询不需要的关联对象。
  • 方案3:打断双向关联的转换依赖
    如果接口不需要返回角色关联数据,UserDto不要定义userRoleDomains对应的属性,ObjectMapper转换时会自动忽略实体中不存在对应DTO字段的属性,不会触发关联集合的加载和哈希计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 06:51:02