반응형
Class User{
@OneToMany
List<Order> orderList;
@OneToMany
List<Coupon> couponList;
}
Class Order{
...
}
Class Coupon{
...
}
위와 같은 구조에서 User의 두 가지 OneToMany인 order정보와 coupon정보를 한번에 모두 가져와야하는경우 fetch join으로 한번에 가져오거나 혹은 둘 다 Eager를 설정하는등의 방법이 생각난다.
하지만 JPA 입장에서 생각을해보면 애매해진다.
먼저 일반적인 OneToMany fetch조인의 동작방식을 생각해보자
1. jpql을 SQL의 join문으로 변경되서 DB에서 실행됨
2. DB에서 row단위로 NxM개의 row가 JPA에 전달됨
3. JPA는 전달받은 데이터를 각 엔티티의 id를 기반으로 데이터를 조합해서 주어진 형태의 Entity로 구성
이제 2개 이상의 OneToMany fetch조인의 동작방식을 생각해보자
1. JPQL에서 변환된 SQL이 DB에서 실행됨
2. DB에서 row단위로 NxMxL 개의 row가 DB에서 전달됨
3. JPA는 전달받은 데이터를 각 엔티티의 id를 기반으로 데이터를 조합을 시도함.
4. 하지만 row를 분석하다보면 User(N)xOrder(M)xCoupon(L) 을 조합한 row가 전달됐기 때문에
User가 가진 Order id가 L개가 나올것이고 JPA입장에서는 어느게 진짜인지 알 수가 없다.
위와 같은 이유로 JPA는 2개 이상의 ToMany를 한번에 가져오지 못하게 만들어졌다.
해결책 : hibernate.default_batch_fetch_size
hibernate.default_batch_fetch_size : 옵션값으로 지정된 수 만큼 부모의 key를 in 절로 사용할 수 있게하는 옵션
예시에서 default_batch_fetch_size을 알 수 있다.
spring.jpa.properties.hibernate.default_batch_fetch_size=100
/// User 3개이며 각 User당 Order 2개 Coupon2개를 가지고있는 상태
User userList = userRepository.findAll();
System.out.println(userList);
/**
* 위 코드에서 실행되는 SQL
* select ... from user;
* select ... from order in (... , ... , ...)
* select ... from coupon in (... , ... , ...)
*/
위의 실행된 SQL과 같이 in절을 이용해서 order와 coupon 한번씩만 접근해서 데이터를 가져온 뒤 조합하여 주어진 Entity형태로 구성하게 된다.
user의 결과가 default_batch_fetch_size보다 많다면 [user의 결과수 ÷ default_batch_fetch_size값] 번으로 나눠서 in 쿼리가 실행된다.
반응형
'JPA' 카테고리의 다른 글
Proxy형태로 동작하는 JPA @Transactional (8) | 2021.02.10 |
---|---|
[JPA] OneToOne 성능 튜닝 사례 1 (1) | 2020.08.18 |
JPQL과 영속성 컨텍스트의 관계 (1) | 2020.07.17 |
LazyInitializationException- no session(준영속상태에서의 참조) (0) | 2020.07.11 |
JPA :: 영속성 컨텍스트 (0) | 2020.07.10 |