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

Spring Boot中Lombok+Hibernate实体报HashMap.hash栈溢出错误

错误根因

你遇到的StackOverflowError是双向关联实体类的循环hash调用导致的:

  • Goal和User是双向关联关系,你用Lombok默认生成的hashCode方法会自动包含所有类字段
  • 计算Goal的哈希值时会调用关联User对象的hashCode,计算User的哈希值时又会遍历goalSet调用每个Goal的hashCode,最终形成无限递归,触发栈溢出
  • 报错触发在HashMap.hash方法是因为你把查询结果收集为HashSet时,会自动调用每个元素的hashCode方法,刚好触发递归逻辑

解决方案

1. 排除关联字段,避免Lombok生成循环逻辑

在两个实体的关联字段上添加@EqualsAndHashCode.Exclude和@ToString.Exclude注解,让Lombok生成hashCode、equals、toString方法时跳过这些关联字段:
Goal实体修改:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
@OnDelete(action = OnDeleteAction.CASCADE)
@EqualsAndHashCode.Exclude
@ToString.Exclude
private User userss;

User实体修改:

// 按需加载改为LAZY,避免每次查询User都强制拉取所有关联Goal,提升性能
@OneToMany(mappedBy = "userss", fetch = FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE)
@EqualsAndHashCode.Exclude
@ToString.Exclude
private Set<Goal> goalSet = new HashSet<>();

2. 优化查询方法写法

指定HQL查询的返回类型,避免无意义的强转和裸类型使用:
按用户ID查询目标集:

@Override
public Set<Goal> findByUserId(Long userId){
   return getSession().createQuery("from Goal where userss.id =:userId", Goal.class)
           .setParameter("userId", userId)
           .stream()
           .collect(Collectors.toSet());
}

查询所有目标:

@Override
public Set<Goal> getGoals() {
    return getSession().createQuery("from Goal", Goal.class)
            .stream()
            .collect(Collectors.toSet());
}

3. 进阶优化(可选)

如果对外返回数据不需要返回完整实体,可以自定义DTO类接收查询结果,从根源上避免实体类的循环依赖问题暴露到外部调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 05:06:05