MultipleBagFetchException 발생시 해결 방법

JPA에서 Fetch Join과 Pagination을 함께 사용할때 주의하자

Untitled

페치 조인이랑 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());
}