초기 코드
@Builder.Default
@OneToMany(mappedBy = "profile", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PreferLocation> preferLocations = new ArrayList<>();
@Builder.Default
@OneToMany(mappedBy = "profile", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PreferPrice> preferPrices = new ArrayList<>();
@Builder.Default
@OneToMany(mappedBy = "profile", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PreferStyle> preferStyles = new ArrayList<>();
@Builder.Default
@OneToMany(mappedBy = "profile", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Award> awards = new ArrayList<>();
@Builder.Default
@OneToMany(mappedBy = "profile", cascade = CascadeType.ALL, orphanRemoval = true)
private List<WorkExperience> workExperiences = new ArrayList<>();
OneToMany 관계의 엔티티들이 있습니다.
그리고 이 엔팉티의 자식들을 모두 가져와야 하는 서비스 메소드가 있습니다.
이때 조회된 부모의 수만큼 자식 테이블의 쿼리가 추가 발생하는 JPA N+1 문제가 발생합니다. 이를 해결하기 위해서 Fetch Join을 적용하였습니다.
@Query("SELECT p FROM Profile p " +
"INNER JOIN FETCH p.user " +
"LEFT JOIN FETCH p.preferStyles " +
"LEFT JOIN FETCH p.preferLocations " +
"LEFT JOIN FETCH p.preferPrices " +
"LEFT JOIN FETCH p.awards " +
"LEFT JOIN FETCH p.workExperiences " +
"WHERE p.isDeleted = false")
Page<Profile> findAllByIsDeletedFalse(Pageable pageable);
이때 1:N 관계의 자식 테이블 여러곳에 Fetch Join을 사용하면 아래와 같은 에러가 발생합니다.
cannot simultaneously fetch multiple bags:
[com.tk.gg.users.domain.model.Profile.awards, com.tk.gg.users.domain.model.Profile.preferLocations]
⇒ JPA에서 Fetch Join 조건으로 XToOne으로 연관되어 있는 엔티티는 몇 개든 조회가능하지만, XToMany로 연관되어 있는 엔티티는 1개만 가능하다. 따라서 OneToMany로 5개를 Fetch Join을 통해서 가져오려고 하니 MultipleBagFetchException 에러가 발생한 것이다.