문제
프로젝트를 진행하다가
org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
이런 에러가 떴다.
원인
하나의 Member 엔티티에서
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<ProfileImage> profileImages;
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<Fever> fevers;
두 개의 OneToMany 연관관계를 가지고 있었는데,
@Query("SELECT m FROM Member m " +
"LEFT JOIN FETCH m.profileImages pi " +
"LEFT JOIN FETCH m.fevers f " +
"WHERE m.uuidSocialMember = :id " +
"AND m.isDeleted = FALSE")
Optional<Member> findWithImagesAndFeversByIdAndIsDeletedIsFalse(UUID id);
이렇게 두 개를 JOIN FETCH 하니까 발생한 것이었다.
이 예외는 여러 Bag를 동시에 fetch하려고 할 때 발생한다고 한다.
Bag(Multiset)은 Set과 같이 순서가 없고, List와 같이 중복을 허용하는 자료구조인데,
Java의 Collection에는 Bag 자료구조가 없기 때문에 Hibernate에서는 List를 Bag로 사용하고 있기 때문에 발생한 것..!
해결 방법
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<ProfileImage> profileImages;
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<Fever> fevers;
Set 자료구조로 바꿔주기
자세히는 좀 더 알아봐야 할 것 같음.
저렇게 해결했었는데, 내가 나중에 내린 결론은 일대다 관계의 엔티티는 웬만하면 join fetch를 하지 말자..였다.
왜냐하면 cartesian product 문제로 인해 엔티티 결과가 중복으로 조회될 수 있다.
뭐가 정답인지는 아직 잘 모르겠다.
'* > Spring' 카테고리의 다른 글
[Spring Boot] 동시성 제어 (1) - 동시성 문제, 재고 감소 시스템 구현 및 테스트 (1) | 2024.11.09 |
---|---|
[JPA] 엔티티 equals 메서드 구현 시 주의할 점 (0) | 2024.11.08 |
[Spring] OpenFeign 사용해보기 (0) | 2024.05.22 |
[JPA] 엔티티 생성 시 생겼던 문제들 (식별관계 문제) (0) | 2024.03.17 |
Java 통신 인터페이스 실습 (0) | 2023.12.30 |