728x90
반응형
[JPA] MultipleBagFetchException 해결
환경 : Spring Boot 3.x, JPA, Hibernate
에러 메시지
org.hibernate.loader.MultipleBagFetchException:
cannot simultaneously fetch multiple bags:
[com.example.Member.orders, com.example.Member.addresses]
1. 원인
2개 이상의 컬렉션(List)을 동시에 fetch join 하면 발생. Hibernate가 카테시안 곱 결과를 올바르게 매핑할 수 없기 때문
@Entity
class Member(
@OneToMany(mappedBy = "member")
val orders: List<Order> = mutableListOf(),
@OneToMany(mappedBy = "member")
val addresses: List<Address> = mutableListOf()
)
// 이 쿼리에서 터짐
@Query("SELECT m FROM Member m JOIN FETCH m.orders JOIN FETCH m.addresses")
fun findAllWithOrdersAndAddresses(): List<Member>
2. 해결 방법
2.1) List를 Set으로 변경
가장 간단한 방법. Set은 중복을 허용하지 않아 카테시안 곱 문제가 발생하지 않음
@Entity
class Member(
@OneToMany(mappedBy = "member")
val orders: Set<Order> = mutableSetOf(),
@OneToMany(mappedBy = "member")
val addresses: Set<Address> = mutableSetOf()
)
※ 순서가 필요하면 LinkedHashSet 사용
2.2) @BatchSize로 분리 조회
fetch join 대신 @BatchSize로 IN 절 조회. 쿼리 2~3번으로 해결
@Entity
class Member(
@OneToMany(mappedBy = "member")
@BatchSize(size = 100)
val orders: List<Order> = mutableListOf(),
@OneToMany(mappedBy = "member")
@BatchSize(size = 100)
val addresses: List<Address> = mutableListOf()
)
# 또는 전역 설정
spring:
jpa:
properties:
hibernate:
default_batch_fetch_size: 100
2.3) fetch join을 나눠서 실행
한 번에 하나의 컬렉션만 fetch join하고 나머지는 Hibernate 초기화에 맡기기
@Query("SELECT m FROM Member m JOIN FETCH m.orders")
fun findAllWithOrders(): List<Member>
// addresses는 @BatchSize 또는 별도 조회로 처리
728x90
반응형
'TroubleShooting' 카테고리의 다른 글
| [vue] CORS 해결 (1) | 2022.06.19 |
|---|---|
| [Vue] You are using the runtime-only build of Vue where the template compiler is not available. (0) | 2020.09.07 |
| [IntelliJ] Git 관련 작업 시 hangs on/Holding (0) | 2020.06.16 |
| [Java-stream] Map 변환 중 Duplicate key (0) | 2020.06.13 |
| [Spring] Expiring Daemon because JVM heap space is exhausted (0) | 2020.03.27 |