본문 바로가기
Java & Kotlin/Spring Data

[QueryDSL] 페이징 연동하기

by heekng 2022. 5. 15.
반응형

페이징 연동하기

Spring Data JPA에서 Page와 Pageable을 이용하고, QueryDSL을 이용하여 페이징을 사용해보자.

가장 효율적인 방법

  • 이전까지의 페이징 방법중 하나는 fetchCount()와 fetchResult()를 이용하는 방법이였다.
  • 하지만 이는 단순히 count 처리하는 용도이기 때문에 QueryDSL에서는 이를 지원하지 않기로 결정했다고 한다.
  • 따라서 count와 result를 더 효율적으로 이용하는 방법을 사용하자.
List<MemberTeamDto> content = queryFactory
    .select(
            new QMemberTeamDto(
                    member.id.as("memberId"),
                    member.username,
                    member.age,
                    team.id.as("teamId"),
                    team.name.as("teamName")
            )
    )
    .from(member)
    .leftJoin(member.team, team)
    .where(
            usernameEq(condition.getUsername()),
            teamNameEq(condition.getTeamName()),
            ageGoe(condition.getAgeGoe()),
            ageLoe(condition.getAgeLoe())
    )
    .offset(pageable.getOffset())
    .limit(pageable.getPageSize())
    .fetch();

JPAQuery<Member> countQuery = queryFactory
    .select(member)
    .from(member)
    .leftJoin(member.team, team)
    .where(
            usernameEq(condition.getUsername()),
            teamNameEq(condition.getTeamName()),
            ageGoe(condition.getAgeGoe()),
            ageLoe(condition.getAgeLoe())
    );

return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchCount);
  • 위 방법은 offsetlimit을 이용해 페이징 처리를 하고, 필요 조건에 따라 전체 count를 조회하여 페이징 정보를 제공하는 코드이다.
  • 먼저 기존과 동일하게 contents를 가져오지만 fetchResults()를 이용하지 않고 fetch()를 사용한다.
  • 이는 당장 필요한 페이징 처리된 contents만 받아온다.
  • 중요한 점은 PageableExecutionUtils.getPage(content, pageable, countQuery::fetchCount)이다.
    • PageableExecutionUtilsspringframework에서 제공하는 페이징처리를 돕는 util이다.
    • PageableExecutionUtils.getPage(컨텐츠 내용, 해당 쿼리에서 이용한 pageable객체, 전체 데이터 개수가 필요한 경우 사용할 count JPAQuery)를 이용하면 pageablecontent를 확인하여 상황에 따라 count 쿼리를 호출하여 결과 Page 객체를 제공한다.
  • 이렇게 페이징이 가능한 이유는 다음과 같다.
    • 현재 조회된 페이지의 contents 개수가 pageable.getPageSize()보다 작은 경우
      -> 현재 페이지 이전 페이지 수 * 페이지 최대 사이즈 + 현재 페이지의 contents 개수 의 연산 결과가 곧 전체 contents의 개수이기 때문에 굳이 count쿼리를 조회하지 않아도 전체 count를 알 수 있다.
  • 이러한 방법을 이용한 페이징은 count 쿼리에 불필요한 join을 제거할 수 있어 성능을 최적화 할 수 있다.
  • 또한 코드 리펙토링시에 내용쿼리와 카운트쿼리를 구분지어 가독성이 좋아진다.
반응형