Spring Boot JPA查询中出现未指定关联实体的问题求助
Spring Data JPA懒加载集合意外加载问题
开发Spring Data JPA应用时遇到一个奇怪的问题:原本认为懒加载(FetchType.LAZY)的集合类型实体仅在实际访问或通过fetch join查询时才会被加载,但调试时发现了一个未在查询的select、from或where子句中指定的ProjectMember实体。
实体类代码
Project实体
@Entity @Table(name = "projects") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Project extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name") private String name; @OneToMany(mappedBy = "project", cascade = CascadeType.ALL, orphanRemoval = true) private final List<ProjectGroup> groups = new ArrayList<>(); @OneToMany(mappedBy = "project", cascade = CascadeType.ALL, orphanRemoval = true) private final List<ProjectMember> projectMembers = new ArrayList<>(); @Builder public Project( String name ) { this.name = name; } public void addGroup(ProjectGroup group) { this.groups.add(group); group.setProject(this); } public void removeGroup(ProjectGroup group) { this.groups.remove(group); group.setProject(null); } public void addProjectMember(ProjectMember projectMember) { this.projectMembers.add(projectMember); projectMember.setProject(this); } public void removeProjectMember(ProjectMember projectMember) { this.projectMembers.remove(projectMember); projectMember.setProject(null); } }
ProjectGroup实体
@Entity @Table(name = "project_groups") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class ProjectGroup extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name") private String name; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "project_id", foreignKey = @ForeignKey(name = "FK_PROJECT_GROUP_PROJECT")) private Project project; @Builder public ProjectGroup(String name) { this.name = name; } public void setProject(Project project) { this.project = project; } }
ProjectMember实体
@Entity @Table(name = "project_members") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class ProjectMember extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "project_id", foreignKey = @ForeignKey(name = "FK_PROJECT_MEMBER_PROJECT")) private Project project; @Column(name = "nickname") private String nickname; @Column(name = "is_deleted") private boolean isDeleted = false; @Builder public ProjectMember( String nickname, boolean isDeleted ) { this.nickname = nickname; this.isDeleted = isDeleted; } public void setProject(Project project) { this.project = project; } }
所有集合类型实体都设置为FetchType.LAZY(默认值)。
Repository与Service代码
ProjectRepository
public interface ProjectRepository extends JpaRepository<Project, Long> { @Query(""" select distinct p from Project p left join fetch p.groups where p.id = :id """) Optional<Project> findWithProjectGroupsById(@Param("id") Long id); }
ProjectQueryServiceImpl
@Service @Transactional @RequiredArgsConstructor public class ProjectQueryServiceImpl implements ProjectQueryService { private final ProjectRepository projectRepository; @Override public ProjectResponseDto fetchWithMembersAndGroups(Long id) { return projectRepository.findWithProjectGroupsById(id) .map(ProjectResponseDto::new) .orElseThrow(EntityNotFoundException::new); } }
Service仅通过fetch join查询Project及其关联的groups实体,查询中完全没有涉及ProjectMember实体。
生成的SQL
select distinct project0_.id as id1_2_0_, groups1_.id as id1_0_1_, project0_.created_at as created_2_2_0_, project0_.modified_at as modified3_2_0_, project0_.name as name4_2_0_, groups1_.created_at as created_2_0_1_, groups1_.modified_at as modified3_0_1_, groups1_.name as name4_0_1_, groups1_.project_id as project_5_0_1_, groups1_.project_id as project_5_0_0__, groups1_.id as id1_0_0__ from projects project0_ left outer join project_groups groups1_ on project0_.id=groups1_.project_id where project0_.id=?
问题现象
在该查询执行后设置断点调试时,发现未指定的ProjectMember实体已被加载(调试截图显示该集合包含数据)。
有人知道这是为什么吗?尝试查找原因但仍未找到。可通过示例代码仓库复现,运行测试方法并在PostResponseDto中设置断点,执行Repository方法后暂停测试即可复现。
内容的提问来源于stack exchange,提问作者I have 10 fingers
相关产品推荐
相关产品推荐

