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

Hibernate中已加载的Map<User, Friendship>无法通过原User对象获取关联Friendship的问题排查

问题根源分析

这个问题的核心是你用来查询Map的f1对象,和fetchedUser.getFriendships()里作为key的User实例,并不是"equals相等"的,导致HashMap无法匹配到对应的value。

具体来说:

  1. 你创建的原始f1对象,在执行userRepo.save(u1)之前,它的id是int类型的默认值0(因为还没被持久化到数据库)。
  2. 虽然cascade=CascadeType.ALL会把f1也保存到数据库,数据库会给它分配id=2,但你的原始f1对象的id值并没有被更新——JPA的save()方法会返回持久化后的实体,但你没有把返回值重新赋值给f1,所以f1的id还是0。
  3. 当你从数据库加载fetchedUser时,Hibernate会创建一个全新的User实例来对应username=friend1的记录,这个实例的id是2。
  4. 你重写的equals方法里,把id作为核心比较字段之一,同时还加入了friendships、posts这些集合字段。这就导致原始f1(id=0)和数据库加载的User实例(id=2)调用equals()时返回false。
  5. HashMap的get()方法依赖key的equals()和hashCode()来匹配条目,所以用原始f1作为key自然找不到对应的Friendship。

而你打印fetchedUser时能看到条目,是因为控制台输出的是Hibernate加载的那个id=2的User实例,它才是Map里真正的key。

解决方案

1. 修正JPA实体的equals和hashCode(根本解决)

对于JPA实体,equals和hashCode的编写有个基本原则:不要依赖可变的字段(比如未持久化时的id,或者集合类字段),应该基于业务唯一标识(比如username,因为它是你创建时就确定且唯一的),或者处理好id未赋值的情况。

推荐的写法如下:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof User)) return false;
    User user = (User) o;
    // 优先用业务唯一字段username比较,避免未持久化时id为0的问题
    return Objects.equals(username, user.username);
}

@Override
public int hashCode() {
    return Objects.hash(username);
}

如果你更倾向于用数据库id,也可以这样处理(兼容未持久化的实体):

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof User)) return false;
    User user = (User) o;
    // 当id不为0时用id比较,未持久化时用内存地址区分
    if (id != 0 && user.id != 0) {
        return id == user.id;
    }
    return System.identityHashCode(this) == System.identityHashCode(user);
}

@Override
public int hashCode() {
    return id != 0 ? Objects.hash(id) : System.identityHashCode(this);
}

2. 临时快速解决(不推荐长期使用)

如果你只是想快速验证结果,可以在保存后重新获取持久化后的f1实例:

// 保存后接收返回的持久化实体
u1 = userRepo.save(u1);
// 重新从数据库查询f1
User f1FromDb = userRepo.findByUsername("friend1");
// 用查询出来的实例去get
System.out.println(fetchedUser.getFriendships().get(f1FromDb));

这个方法能临时解决问题,但本质上没有修复实体equals/hashCode的设计缺陷,不建议在生产代码中使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 10:27:34