MultipleBagFetchException 발생시 해결 방법
JPA에서 Fetch Join과 Pagination을 함께 사용할때 주의하자
페치 조인이랑 Paging을 동시에 하면 안된다는걸 알았다.
HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!
라는 에러 메세지를 마주침으로써 위 사실을 알게 되었는데, 이에 대해 해결해보고자 한다.
위 에러 로그는, 쿼리 결과를 전부 메모리에 적재한 뒤 Pagination 작업을 어플리케이션 레벨에서하기 때문에 위험하다는 로그이다.
목적에 맞게 아래와 같이 쿼리를 수정함으로써 해결하였다. 페치 조인은 batch_fetch_size
옵션을 도입함으로써 해결했다.
@Override
public Page<Post> searchPost(PostSearch postSearch, Pageable pageable) {
RecruitType recruitType =
postSearch.getRecruitType().equalsIgnoreCase("TOTAL") ?
null : postSearch.recruitTypeToEnum();
// 조건을 만족하는 post Id만 우선 찾는다. 왜 Id를 찾느냐? 중복을 제거할 수 있는 수단이 Id뿐이다.
List<Long> postIds = jpaQueryFactory
.select(post.id).from(post).distinct()
.innerJoin(post.fieldsList,fields)
.innerJoin(fields.stacks,techStack)
.where(searchPost(recruitType, postSearch.getKeyword()))
.fetch();
// 여기서는 post를 찾아야 한다. 페이징 해서 보내줘야 하기 때문.
JPAQuery<Post> find = jpaQueryFactory.selectFrom(post)
.where(post.isCompleted.eq(false),post.id.in(postIds));
List<Post> totalList = find.fetch();
List<Post> postList = find
.limit(pageable.getPageSize())
.offset(pageable.getOffset())
.orderBy(post.createdDate.desc())
.fetch();
return new PageImpl<>(postList, pageable, totalList.size());
}