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

Spring Boot自关联多对多关系引发StackOverflowError问题解决

StackOverflowError 解决:Spring Boot 自关联用户关注关系

我是Spring Boot和Java新手,最近在做用户关注功能时,用自关联的tb_user表实现双向关注关系,结果触发了StackOverflowError。一开始试了@JsonIgnore和@JsonIdentityInfo注解,都没解决问题,最后通过调整JPA关系映射和业务代码逻辑搞定了,分享一下过程:

原实体类代码

@Entity
@Table(name = "tb_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;

    // 关注的用户
    @ManyToMany
    @JoinTable(
        name = "tb_user_follow",
        joinColumns = @JoinColumn(name = "follower_id"),
        inverseJoinColumns = @JoinColumn(name = "following_id")
    )
    private List<User> following;

    // 粉丝
    @ManyToMany(mappedBy = "following")
    private List<User> followers;

    // IDE自动生成的getter、setter、toString方法
}

报错栈信息

java.lang.StackOverflowError
    at com.example.demo.entity.User.toString(User.java:45)
    at java.base/java.lang.String.valueOf(String.java:3367)
    at java.base/java.lang.StringBuilder.append(StringBuilder.java:168)
    at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:473)
    at com.example.demo.entity.User.toString(User.java:45)
    // 重复递归调用栈省略...

问题根源

  1. toString循环引用:IDE自动生成的toString()会递归打印following和followers集合,导致无限循环调用,直接触发栈溢出。
  2. JSON序列化循环:之前加@JsonIgnore时位置不对,且没处理业务代码中的双向关联遍历;@JsonIdentityInfo未生效是因为没指定正确的生成器配置。

解决步骤

1. 修正实体类映射与注解

调整注解位置,重写toString方法避免递归:

@Entity
@Table(name = "tb_user")
// 配置JSON序列化时用ID标识对象,避免循环
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;

    // 关注列表:序列化时忽略,避免反向递归
    @ManyToMany
    @JoinTable(
        name = "tb_user_follow",
        joinColumns = @JoinColumn(name = "follower_id"),
        inverseJoinColumns = @JoinColumn(name = "following_id")
    )
    @JsonIgnore
    private List<User> following;

    // 粉丝列表:序列化时只返回ID,而非完整对象
    @ManyToMany(mappedBy = "following")
    @JsonSerialize(contentUsing = ToStringSerializer.class)
    private List<User> followers;

    // 重写toString,只打印基础字段,不包含关联集合
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                '}';
    }

    // 自定义getter、setter方法
}

2. 优化业务查询逻辑

避免一次性加载双向关联集合,按需查询:

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    // 查询用户基础信息+粉丝列表(仅加载粉丝基础数据)
    public User getUserWithFollowers(Long userId) {
        return userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
    }

    // 单独提供关注列表查询接口,按需加载
    public List<User> getFollowingList(Long userId) {
        User user = userRepository.findById(userId).orElseThrow();
        return user.getFollowing();
    }
}

3. 验证结果

调整后,toString方法不再递归调用,JSON序列化时也不会触发循环引用,StackOverflowError问题彻底解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 07:28:09