
목차
Querydsl 페이징
| public interface MemberRepositoryCustom {List<MemberTeamDto> search(MemberSearchCondition condition);
 Page<MemberTeamDto> searchPageSimple(MemberSearchCondition condition, Pageable pageable);
 Page<MemberTeamDto> searchPageComplex(MemberSearchCondition condition, Pageable pageable);
 }
 
 | 
QueryDSL 에서 제공하는 fetchResults 를 사용하게 되면 데이터를 가져오는 쿼리 와 가져온 데이터 수를 확인하는 Count 쿼리 총 2개의 쿼리가 발생하게 된다.
| @Overridepublic Page<MemberTeamDto> searchPageSimple(MemberSearchCondition condition, Pageable pageable) {
 QueryResults<MemberTeamDto> results = 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 = results.getResults();
 long total = results.getTotal();
 
 return new PageImpl<>(content, pageable, total);
 }
 
 | 
Querydsl 페이징 쿼리와 Count 쿼리 분리
| @Overridepublic Page<MemberTeamDto> searchPageComplex(MemberSearchCondition condition, Pageable pageable) {
 
 
 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();
 
 
 long total = queryFactory
 .select(ExpressionUtils.count(member))
 .from(member)
 .leftJoin(member.team, team)
 .where(
 usernameEq(condition.getUsername()),
 teamNameEq(condition.getTeamName()),
 ageGoe(condition.getAgeGoe()),
 ageLoe(condition.getAgeLoe())
 )
 .fetchCount();
 
 return new PageImpl<>(content, pageable, total);
 }
 
 | 
스프링 데이터 페이징 활용2 - CountQuery 최적화
- count 쿼리가 생략 가능한 경우 생략해서 처리
- 페이지 시작이면서 컨텐츠 사이즈가 페이지 사이즈 보다 작을때
- 마지막 페이지 일때(offset + 컨텐츠 사이즈를 더해서 전체 사이즈를 구함)
 
PageableExecutionUtils 와 JPAQuery 를 이용
| @Overridepublic Page<MemberTeamDto> searchPageComplex(MemberSearchCondition condition, Pageable pageable) {
 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<Long> countQuery = queryFactory
 .select(count(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());
 }
 
 | 
스프링 데이터 페이징 활용3 - 컨트롤러 개발
| @RestController@RequiredArgsConstructor
 public class MemberController {
 
 private final MemberJpaRepository memberJpaRepository;
 private final MemberRepository memberRepository;
 
 @GetMapping("/v1/members")
 public List<MemberTeamDto> searchMemberV1(MemberSearchCondition condition) {
 return memberJpaRepository.search(condition);
 }
 
 @GetMapping("/v2/members")
 public Page<MemberTeamDto> searchMemberV2(MemberSearchCondition condition, Pageable pageable) {
 return memberRepository.searchPageSimple(condition, pageable);
 }
 
 @GetMapping("/v3/members")
 public Page<MemberTeamDto> searchMemberV3(MemberSearchCondition condition, Pageable pageable) {
 return memberRepository.searchPageComplex(condition, pageable);
 }
 }
 
 |