본문 바로가기
개발/Spring

Paging CountQuery With Querydsl

by solchan98 2023. 10. 25.

기본적인 페이징 방식

  • countQuery를 날려 totalCount 체크
  • 기존 fetchResults()가 Deprecated 되면서 아래 방식으로 해결
@Repository
@RequiredArgsConstructor
public class ItemRepository {

      private final JPAQueryFactory jpaQueryFactory;

      public Page<Item> getItems(Pageable pageable) {
		
      List<Item> items = jpaQueryFactory
          .selectFrom(item)
          .offset(pageable.getOffset())
          .limit(pageable.getPageSize());

      long totalCount = jpaQueryFactory
          .select(item.count())
          .fetchOne();

      return new PageImpl<>(items, pageable, totalCount);
  }
}

향상된 페이징 방식

  • 아래의 조건에 해당되는 경우 countQuery를 날릴 필요가 없음
    1. 첫 페이지이면서, 결과 사이즈가 페이지 사이즈보다 작은 경우
    2. 마지막 페이지인 경우
  • PageableExecutionUtils 사용하여 아래와 같이 적용 가능
    • countQuery를 직접 날리지 않고 LongSupplier로 넘겨 활용
    • 활용 상세 로직은 아래 아래 PageableExecutionUtils 참고
@Repository
@RequiredArgsConstructor
public class ItemRepository {

    private final JPAQueryFactory jpaQueryFactory;

    public Page<Item> getItems(Pageable pageable) {

        List<Item> items = jpaQueryFactory
                .selectFrom(item)
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize());

        JPAQuery<Long> countQuery = jpaQueryFactory.select(item.count());

        return PageableExecutionUtils.getPage(items, pageable, countQuery::fetchOne);
    }
}

PageableExecutionUtils

  • 첫 페이지이면서, fetchSize < pageSize인 경우
    • fetchSize = totalSize
  • 마지막 페이지인 경우
    • pageable.getOffset() + fetchSize = totalSize
      • pageable.getOffset() -> page * size
package org.springframework.data.support;

...

public abstract class PageableExecutionUtils {

	private PageableExecutionUtils() {}

	...
	public static <T> Page<T> getPage(List<T> content, Pageable pageable, LongSupplier totalSupplier) {

		Assert.notNull(content, "Content must not be null");
		Assert.notNull(pageable, "Pageable must not be null");
		Assert.notNull(totalSupplier, "TotalSupplier must not be null");

		if (pageable.isUnpaged() || pageable.getOffset() == 0) { // 첫 페이지인 경우,

			if (pageable.isUnpaged() || pageable.getPageSize() > content.size()) { // 결과 사이즈가 페이지 사이즈 보다 작다면
				return new PageImpl<>(content, pageable, content.size()); // countQuery 호출 X
			}

			return new PageImpl<>(content, pageable, totalSupplier.getAsLong()); // countQuery 호출 O
		}

		if (content.size() != 0 && pageable.getPageSize() > content.size()) { // 마지막 페이지인 경우,
			return new PageImpl<>(content, pageable, pageable.getOffset() + content.size()); // countQuery 호출 X
		}

		return new PageImpl<>(content, pageable, totalSupplier.getAsLong()); // countQuery 호출 O
	}
}

 

참고