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
반응형

+ Recent posts