-
[Spring] MultipleBagFetchExcption 발생 시 해결 방법Spring 2022. 1. 9. 16:39
jpa의 n+1문제를 해결하기 위해 fetch join을 종종 사용한다.
그런데 list로 구현된 연관테이블들에 fetchjoin을 두개이상 하면 발생하는 오류가 있다.
바로 MultipleBagFetchExcption 이다.
주로 2개이상의 ToMany 테이블들을 fetch join을 했을 때 발생한다.
ToOne의 경우 여러번 fetch join을 해도 되지만 ToMany의 경우 한번밖에 fetch join을 쓰지 못한다.
이를 해결하는 방법은 두가지가 있는데
- List로 구현된 ToMany테이블들을 Set으로 바꾸는것
- 하이버네이트의 default_batch_fetch_size 옵션 적용
두가지 방법이 있다.
List로 구현된 ToMany테이블을 Set으로 바꾸는법
MultipleBagFetchExcption 은 원래 백이란 자료구조를 여러개 썼을 경우 발생하는 오류이다.
자바 컬렉션에서는 Bag을 지원하지 않기 때문에 하이버네이트는 List을 Bag으로 활용한다.
List는 순서를 보장하고, 중복을 허용하는 컬렉션이고, Set은 순서를 보장하지 않고, 중복을 허용치 않기 때문에 Bag과 연관성이 없다.
정확한 이유는 확신할 수 없지만, List로 구현된 ToMany테이블들을 Set으로 바꾸면 오류가 발생하지 않는 것을 확인했다.
중복이 없고, 순서를 상관치 않는다면 Set으로 바꿔 구현해봐도 괜찮을 것 같다.
하이버네이트의 default_batch_fetch_size 옵션 적용
하이버네이트의 default_batch_fetch_size 옵션을 사용하면 기존에 하나의 객체마다 한번씩 쿼리가 생성되는 일이 in을 이용하여 한번에 쿼리가 나간다.
ex) (1 + J + M + K) * N개의 행에 대해 1+N+N+N 번 쿼리가 나가던 일이 1 + 1 + 1 + 1으로 줄일 수 있게 된다.
default_batch_fetch_size 옵션은 application.yml 기준으로
spring: jpa: properties: hibernate.default_batch_fetch_size: 1000
이런식으로 설정할수있으며, 최댓값은 1000이다.
default_batch_fetch_size을 통한 쿼리갯수는 무조건 설정값 아래를 한번에 해주는 것이 아닌 일종의 규칙이 있는데,
이는 여기서 확인할 수 있다.
[Spring] default_batch_fetch_size 대로 in쿼리가 나가지 않는 이유 :: 퉁그리노트 (tistory.com)
'Spring' 카테고리의 다른 글
[Spring] 프록시와 연관관계 관리 (0) 2022.01.18 [Spring] spring boot 라이브러리 버전관리 (0) 2022.01.15 [Spring] default_batch_fetch_size 대로 in쿼리가 나가지 않는 이유 (1) 2022.01.09 [Spring] 프로파일 설정을 통해 샘플데이터 추가하기 (0) 2022.01.07 [Spring] querydsl - 수정, 삭제 벌크 연산 (0) 2022.01.05