Spring Boot JPA中仅插入Friend表不更新User表的问题求助
问题:Spring Boot JPA插入Friend表时意外触发User表更新导致"password is null"错误
在处理一对多关联表插入操作时,仅希望向Friend表插入好友请求数据,但控制台输出了User表的更新语句,进而触发"password is null"错误,需要实现仅插入Friend表而不更新User表的逻辑。
User实体类
@Data @NoArgsConstructor @AllArgsConstructor @Builder @Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.UUID) @Column(name = "id", nullable = false) private String id; @Column(name = "name", nullable = false) private String name; @Column(name = "email", nullable = false, unique = true) @Email private String email; @Column(name = "password", nullable = false) private String password; @Column(name = "avatar") private String avatar; @Column(name = "gender", nullable = false) private String gender; @Column(name = "phone") private String phone; @Temporal(TemporalType.DATE) @Column(name = "birth_date", nullable = false) private Date birthDate; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JsonIgnore private List<UserRoom> userRooms; @OneToMany(mappedBy = "myself", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JsonIgnore private List<Friend> myself; @OneToMany(mappedBy = "friend", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JsonIgnore private List<Friend> friend; }
Friend实体类
@Data @NoArgsConstructor @Getter @Setter @ToString @AllArgsConstructor @Builder @Entity @Table(name = "friend", uniqueConstraints = { @UniqueConstraint(columnNames = {"myself_id", "friend_id"}) }) public class Friend { @Id @GeneratedValue(strategy = GenerationType.UUID) @Column(nullable = false) private String id; @NotNull @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) @JoinColumn(name = "myself_id") @JsonIgnore private User myself; @NotNull @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) @JoinColumn(name = "friend_id") @JsonIgnore private User friend; @Enumerated(EnumType.STRING) @Column(name = "relationship", nullable = false) private Relationship relationship; public enum Relationship { NONE, SEND_REQUEST, RECEIVE_REQUEST, FRIEND, BLOCKED, } }
FriendServiceImpl业务实现类
@Override public Object sendFriendRequest(JsonNode info) { String friendId = info.get("friendId").textValue(); String myId = info.get("myId").textValue(); User friendInfo = userService.findUserInformationById(friendId); User myInfo = userService.findUserInformationById(myId); System.out.println(">>>" + friendInfo + " \n" + myInfo); if(friendInfo == null || myInfo == null) { return null; } Friend a = new Friend().builder() .myself(friendInfo) .friend(myInfo) .relationship(Friend.Relationship.RECEIVE_REQUEST) .build(); Object yourNewRelationship = friendRepository.save(a); System.out.println("OKOKOK"); Object myNewRelationship = friendRepository.save( new Friend().builder() .myself(myInfo) .friend(friendInfo) .relationship(Friend.Relationship.SEND_REQUEST) .build() ); return myNewRelationship; }
控制台输出

数据库表结构

解决方法
问题根源
User实体中myself和friend两个@OneToMany关联配置了cascade = CascadeType.ALL,当Friend实体被持久化时,会级联触发User实体的更新操作。- 从
userService.findUserInformationById获取的User对象可能未正确加载password字段(比如查询时未包含该字段、DTO转实体时丢失),导致JPA认为User的password被修改为null,触发更新时违反非空约束。
修复步骤
调整User实体的级联策略
将myself和friend的级联策略改为CascadeType.PERSIST,或直接移除级联配置(因为Friend表插入不需要操作已存在的User表):@OneToMany(mappedBy = "myself", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY) @JsonIgnore private List<Friend> myself; @OneToMany(mappedBy = "friend", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY) @JsonIgnore private List<Friend> friend;若不需要任何级联操作,可设置为
cascade = {}:@OneToMany(mappedBy = "myself", cascade = {}, fetch = FetchType.LAZY) @JsonIgnore private List<Friend> myself;确保User对象的必填字段完整
检查userService.findUserInformationById的实现,确保查询User时加载了所有必填字段(包括password),避免返回的User实体存在null的必填属性。可选:分离持久化上下文的User实体
若必须保留级联策略,可在保存Friend前将User实体从持久化上下文分离,阻止JPA跟踪其状态变化:entityManager.detach(friendInfo); entityManager.detach(myInfo);
内容的提问来源于stack exchange,提问作者An Nguyen
相关产品推荐
相关产品推荐

