searchMemberV1(MemberSearchCondition condition) { return memberJpaRepository.search(condition); } @GetMapping("/v2/members") public Page searchMemberV2(MemberSearchCondition condition, Pageable pageable) { return memberRepository.searchPageSimple(condition, pageable); } @GetMapping("/v3/members") public Page searchMemberV3(MemberSearchCondition condition, Pageable pageable) { return memberRepository.searchPageComplex(condition, pageable); } }"> searchMemberV1(MemberSearchCondition condition) { return memberJpaRepository.search(condition); } @GetMapping("/v2/members") public Page searchMemberV2(MemberSearchCondition condition, Pageable pageable) { return memberRepository.searchPageSimple(condition, pageable); } @GetMapping("/v3/members") public Page searchMemberV3(MemberSearchCondition condition, Pageable pageable) { return memberRepository.searchPageComplex(condition, pageable); } }"> searchMemberV1(MemberSearchCondition condition) { return memberJpaRepository.search(condition); } @GetMapping("/v2/members") public Page searchMemberV2(MemberSearchCondition condition, Pageable pageable) { return memberRepository.searchPageSimple(condition, pageable); } @GetMapping("/v3/members") public Page searchMemberV3(MemberSearchCondition condition, Pageable pageable) { return memberRepository.searchPageComplex(condition, pageable); } }">
@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);
	}
}
  • v3는 count 쿼리가 최적화 된 버전이기 때문에 불필요하게 count 쿼리를 날리지 않는다.
    • 첫 페이지에서 limit 값 보다 작은 데이터가 조회된 경우 전체 데이터가 온 것으로 판단하고 count 쿼리 없이 전체 갯수를 구함
    • 마지막 페이지에서 limit 보다 작은 데이터가 조회된 경우 마지막 페이지이기 때문에 offset + 갯수로 count 구함

스프링 데이터 정렬

스프링 데이터 JPA의 sort를 querydsl에서 깔끔하게 쓸 수 있도록 제공하는 인터페이스가 있다. 그런데 join의 경우 안된다. 복잡해 지면 파라미터를 받아서 그때그때 order by 조건을 만들어야 한다.

<aside> 💡 그냥 처음부터 파라미터로 받아서 쓰는게 어떨까..

</aside>

영한님 의견

Sort는 조건이 조금만 복잡해져도 PageableSort 기능을 사용하기 어렵다. 루트 엔티티 범위를 넘어가는 (join 되는) 동적 정렬이 필요하면 스프링 데이터 페이징이 제공하는 Sort를 사용하기 보다는 파라미터를 직접 받아서 처리하는 것을 권장한다.

스프링 데이터 Sort를 Querydsl의 OrderSpecifier로 변환하는 코드

JPAQuery<Member> query = queryFactory
				.selectFrom(member);
		for (Sort.Order o : pageable.getSort()) {
			PathBuilder pathBuilder = new PathBuilder(member.getType(),
					member.getMetadata());
			query.orderBy(new OrderSpecifier(o.isAscending() ? Order.ASC : Order.DESC,
					pathBuilder.get(o.getProperty()))); List<Member> result = query.fetch();