Spring Data JPA는 페이징 처리를 위해 Pageable, Page 인터페이스와 Page 구현체인 PageImpl를 제공한다.
Pageable
/**
* Abstract interface for pagination information.
*/
public interface Pageable { ... }
Page
/**
* A page is a sublist of a list of objects. It allows gain information about the position of it in the containing
* entire list.
*
* @param <T>
*/
public interface Page<T> extends Slice<T> { ... }
PageImpl
/**
* Basic {@code Page} implementation.
*
* @param <T> the type of which the page consists.
*/
public class PageImpl<T> extends Chunk<T> implements Page<T> {
private static final long serialVersionUID = 867755909294344406L;
private final long total;
/**
* Constructor of {@code PageImpl}.
*
* @param content the content of this page, must not be {@literal null}.
* @param pageable the paging information, must not be {@literal null}.
* @param total the total amount of items available. The total might be adapted considering the length of the content
* given, if it is going to be the content of the last page. This is in place to mitigate inconsistencies.
*/
public PageImpl(List<T> content, Pageable pageable, long total) {
super(content, pageable);
this.total = pageable.toOptional().filter(it -> !content.isEmpty())//
.filter(it -> it.getOffset() + it.getPageSize() > total)//
.map(it -> it.getOffset() + content.size())//
.orElse(total);
}
/**
* Creates a new {@link PageImpl} with the given content. This will result in the created {@link Page} being identical
* to the entire {@link List}.
*
* @param content must not be {@literal null}.
*/
public PageImpl(List<T> content) {
this(content, Pageable.unpaged(), null == content ? 0 : content.size());
}
MemberRepositoryCustom
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import study.querydsl.dto.MemberSearchCondition;
import study.querydsl.dto.MemberTeamDto;
public interface MemberRepositoryCustom {
Page<MemberTeamDto> searchPageSimple(MemberSearchCondition condition, Pageable pageable);
Page<MemberTeamDto> searchPageComplex(MemberSearchCondition condition, Pageable pageable);
}
반환값은 Page<MemberTeamDto>이며 Pageable 전달
사용자 정의 레퍼지토리에 정의한 메서드 구현
조회 쿼리와 total count 쿼리 한번에 실행 (발생되는 쿼리는 2번)
@Override
public Page<MemberTeamDto> searchPageSimple(MemberSearchCondition condition, Pageable pageable) {
QueryResults<MemberTeamDto> result = 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())
.fetchResults();
List<MemberTeamDto> content = result.getResults();
long total = result.getTotal();
return new PageImpl<>(content, pageable, total);
}
count 쿼리 시 필요없는 order by는 알아서 제외
조회 쿼리와 total count 쿼리 분리
데이터 조회용 쿼리와 전체 사이즈를 조회하는 쿼리 따로 관리
import org.springframework.data.support.PageableExecutionUtils;
@Override
public Page<MemberTeamDto> searchPageComplex(MemberSearchCondition condition, Pageable pageable) {
//content
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();
// count
JPAQuery<Member> countQeury = 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());
return PageableExecutionUtils.getPage(content, pageable, countQeury::fetchCount);
}
PageableExecutionUtils 이용하여 필요 시에만 count 쿼리 실행 가능
- 스프링 데이터 라이브러리가 제공하며 count 쿼리가 생략 가능한 경우 생략해서 처리한다.
예) 페이지 시작이면서 컨텐츠 사이즈가 페이지 사이즈보다 작을 때 전체 사이즈가 필요 없음, 마지막 페이지 일 때 offset + 컨텐츠 사이즈를 더하면 전체 사이즈 조회 가능
MemberController
import org.springframework.data.domain.Pageable;
@GetMapping("/paging/members")
public Page<MemberTeamDto> searchMember(MemberSearchCondition condition, Pageable pageable) {
return memberRepository.searchPageComplex(condition, pageable);
}
동일하게 반환값은 Page<MemberTeamDto>
실행 결과 조회 결과 size 개수대로 데이터와 페이징 현황을 보여줌
http://localhost:8080/paging/members?page=0&size=5
[JAVA] 자바 자료형, Integer와 int의 차이에 대해 (0) | 2021.08.26 |
---|---|
[JAVA] 객체의 생성과 표현 방법 (1) | 2021.08.23 |
[SPRING] Querydsl | 스프링 데이터 JPA와 Querydsl (0) | 2021.05.17 |
[SPRING] Querydsl | 벌크 연산 (0) | 2021.05.17 |
[SPRING] Querydsl | 동적쿼리 (0) | 2021.05.17 |
댓글 영역