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

Spring Data JPA调用saveAllAndFlush仅插入单条角色数据问题排查

Spring Data JPA 数据插入与关联查询问题排查

一、Roles表仅插入1条记录的原因及修复

问题根因

你的Roles实体将userId设为唯一主键,而你生成的4条角色数据的userId完全相同(都属于同一个用户)。数据库主键具有唯一性约束,后续插入的同主键数据会直接覆盖之前的记录,最终只保留最后一条。

修复方案

根据业务需求选择以下两种方案:

  • 方案1:给Roles添加独立主键(支持同一用户重复拥有相同角色)
    适配你的JSON中存在重复角色的场景,修改Roles实体:
@Getter@Setter@Builder@AllArgsConstructor@NoArgsConstructor
@Entity@Table(name="roles")
public class Roles {
    @Id
    @GeneratedValue
    private UUID id; // 新增独立主键
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private Users user; // 关联Users实体,替代原userId字段
    @Column(name="role_code",nullable=false)
    private String roleCode;
    @Column(name="system_type",nullable=false)
    private String systemType;
    private OffsetDateTime createdAt; // 保留原有字段
}

插入代码中,将userId(users1.getId())改为user(users1)即可。

  • 方案2:使用复合主键(同一用户的角色唯一由roleCode+systemType决定)
    若业务不允许同一用户重复拥有相同角色,可创建复合主键:
// 复合主键类,需实现Serializable并重写equals、hashCode
@Embeddable
@Getter@Setter@EqualsAndHashCode
public class RolePK implements Serializable {
    @Column(name="user_id")
    private UUID userId;
    @Column(name="role_code")
    private String roleCode;
    @Column(name="system_type")
    private String systemType;
}

// 修改Roles实体
@Getter@Setter@Builder@AllArgsConstructor@NoArgsConstructor
@Entity@Table(name="roles")
public class Roles {
    @EmbeddedId
    private RolePK id;
    private OffsetDateTime createdAt;
}

二、EntityGraph关联查询返回roles为空对象的原因及修复

问题根因

  1. 实体无关联关系:Users实体中未定义与Roles的关联字段,@EntityGraph(attributePaths = "roles")中的roles属性不存在,Hibernate无法执行关联查询。
  2. 数据无法映射:即使数据库中有Roles数据,由于没有关联映射,无法自动封装到Users对象中;返回的空对象集合是因为DTO转换时创建了与原列表长度一致的空对象,但未填充属性。

修复方案

  1. 建立实体双向关联
    在Users实体中添加@OneToMany关联:
@Getter@Setter@Builder@AllArgsConstructor@NoArgsConstructor
@Entity@Table(name="users")
public class Users {
    @Id@GeneratedValue
    private UUID id;
    @Column(name="login_name",unique=true,nullable=false)
    private String loginName;
    @Column(name="password",nullable=false)
    private String password;
    @Column(name="email",unique=true,nullable=false)
    private String email;
    @Column(name="status",nullable=false,length=10)
    @Enumerated(EnumType.STRING)
    private UserStatus status;
    @Column(name="full_name") // 补充代码中用到的fullName字段
    private String fullName;
    // 添加与Roles的关联
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Roles> roles = new ArrayList<>();
}

确保Roles实体使用方案1中的关联配置(@ManyToOne关联Users)。

  1. 验证关联查询
    此时你的UserRepository中的findById方法可以正常通过@EntityGraph关联查询roles数据。

  2. 检查DTO转换逻辑
    确保将Users实体的roles集合正确映射到UserRequestDto的roles字段,示例手动转换:

UserRequestDto dto = UserRequestDto.builder()
        .loginName(users.getLoginName())
        .email(users.getEmail())
        .status(users.getStatus())
        .roles(users.getRoles().stream()
                .map(role -> UserRoleDto.builder()
                        .roleCode(role.getRoleCode())
                        .systemType(role.getSystemType())
                        .build())
                .collect(Collectors.toList()))
        .build();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:05:19