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

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;
}

控制台输出

控制台输出截图

数据库表结构

数据库表结构示意图


解决方法

问题根源

  1. User实体中myself和friend两个@OneToMany关联配置了cascade = CascadeType.ALL,当Friend实体被持久化时,会级联触发User实体的更新操作。
  2. 从userService.findUserInformationById获取的User对象可能未正确加载password字段(比如查询时未包含该字段、DTO转实体时丢失),导致JPA认为User的password被修改为null,触发更新时违反非空约束。

修复步骤

  1. 调整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;
    
  2. 确保User对象的必填字段完整
    检查userService.findUserInformationById的实现,确保查询User时加载了所有必填字段(包括password),避免返回的User实体存在null的必填属性。

  3. 可选:分离持久化上下文的User实体
    若必须保留级联策略,可在保存Friend前将User实体从持久化上下文分离,阻止JPA跟踪其状态变化:

    entityManager.detach(friendInfo);
    entityManager.detach(myInfo);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 06:55:14