Spring Boot REST JPA粉丝表双用户外键复合主键实现方法
JPA粉丝表双外键复合主键实现方案
同表自关联场景下的双外键复合主键,和跨表关联的复合主键实现逻辑没有任何区别——复合主键本质是存储两个外键的关联ID值,和外键指向的表是否为同一张无关,直接按照JPA复合主键规范改造代码即可,不需要额外做特殊适配。
实现步骤
1. 定义复合主键嵌入类
新建主键类,满足三个要求:添加@Embeddable注解、实现Serializable接口、重写equals和hashCode方法,字段对应两个关联用户的ID:
import jakarta.persistence.Embeddable; import java.io.Serializable; import java.util.Objects; @Embeddable public class FollowersId implements Serializable { // 对应关注发起方用户ID,类型和User表主键类型保持一致 private Integer fromUserId; // 对应被关注方用户ID private Integer toUserId; public FollowersId() {} public FollowersId(Integer fromUserId, Integer toUserId) { this.fromUserId = fromUserId; this.toUserId = toUserId; } // 自行生成两个字段的getter、setter方法 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; FollowersId that = (FollowersId) o; return Objects.equals(fromUserId, that.fromUserId) && Objects.equals(toUserId, that.toUserId); } @Override public int hashCode() { return Objects.hash(fromUserId, toUserId); } }
如果你使用的是旧版JPA依赖,把代码中
jakarta.persistence包路径替换为javax.persistence即可。
2. 改造Followers实体类
删除原有的独立自增ID字段,用@EmbeddedId声明复合主键,同时给两个外键关联字段添加@MapsId注解,绑定外键和复合主键内的对应字段:
import jakarta.persistence.*; @Entity public class Followers { @EmbeddedId private FollowersId id; @ManyToOne @MapsId("fromUserId") // 绑定复合主键中的fromUserId字段 @JoinColumn(name = "from_user_fk") private User from; @ManyToOne @MapsId("toUserId") // 绑定复合主键中的toUserId字段 @JoinColumn(name = "to_user_fk") private User to; public Followers() {}; public Followers(User from, User to) { this.from = from; this.to = to; // 构造关联关系时同步给复合主键赋值 this.id = new FollowersId(from.getId(), to.getId()); } // 自行生成from、to字段的getter、setter方法 }
注意事项
- User实体类不需要做任何修改,原有配置的
@OneToMany粉丝、关注列表映射可以正常工作 - 复合主键不需要配置生成策略,插入数据时只要给
from、to两个字段赋值正确的User对象,JPA会自动拼装主键值 - 该结构天然自带业务唯一性约束:同一个用户无法重复关注另一个用户,不需要额外添加唯一索引
- 后续需要根据主键查询粉丝关系时,直接构造
new FollowersId(发起关注用户ID, 被关注用户ID)调用findById方法即可,不需要编写复杂的关联查询
结构参考
当前旧表结构:
改造后目标表结构:
内容的提问来源于stack exchange,提问作者Derek Jafet
相关产品推荐
相关产品推荐

