Spring Boot中如何配置User与UserInfo一对一关联(UserInfo存外键)
问题描述
现有Spring Boot项目中的实体类如下:
public class User implements UserDetails { @Id @GeneratedValue private Long id; private String email; private String password; @OneToOne private UserInfo info; } public class UserInfo { @Id @GeneratedValue private Long id; private String firstName; private String lastName; private String birthDay; }
期望按以下方式保存新用户:
User user = User.builder() .email("example@email.se") .password("password") .build(); UserInfo userInfo = UserInfo.builder() .firstName("foo") .lastName("oof") .birthDay("ofo") .build(); user.setInfo(userInfo); repository.save(user);
期望生成的数据库表结构为:
-- USER TABLE id email password
-- USER INFO TABLE user_id firstname lastname birthday
但目前尝试注解后,只有让USER表持有指向UserInfo表的外键时项目才能正常启动,想了解问题所在及解决方法。
解决方案
要实现你期望的表结构,需要调整实体类的关联注解配置,让USER_INFO表以user_id作为主键(同时作为关联USER表的外键),具体修改如下:
- 修改User实体的关联注解
指定关联关系由UserInfo维护,同时开启级联操作,确保保存User时自动保存关联的UserInfo:
public class User implements UserDetails { @Id @GeneratedValue private Long id; private String email; private String password; // mappedBy指定由UserInfo的user字段维护关联,cascade级联所有操作 @OneToOne(mappedBy = "user", cascade = CascadeType.ALL) private UserInfo info; }
- 修改UserInfo实体的主键与关联配置
将UserInfo的主键改为关联User的外键,去掉自增主键:
public class UserInfo { // 将User作为主键,同时指定外键列名为user_id @Id @OneToOne @JoinColumn(name = "user_id") private User user; private String firstName; private String lastName; private String birthDay; }
- 调整保存逻辑(可选)
由于已经配置了cascade = CascadeType.ALL,原有的保存代码可以直接使用,无需额外修改。保存User时,JPA会自动将User的id作为UserInfo的user_id存入数据库。
为什么之前的配置不符合预期?
默认情况下,@OneToOne注解会让持有关联字段的一方(即User类中的info字段)生成外键,所以会在USER表中添加指向UserInfo的外键列。通过mappedBy将关联维护权转移到UserInfo,并将UserInfo的主键设为User的外键,就能实现你期望的表结构,同时保证关联关系的正确性。
内容的提问来源于stack exchange,提问作者Gustav Henriksson
相关产品推荐
相关产品推荐

