본문으로 건너뛰기
Advertisement

9.5 페이징 및 정렬 처리 (Pageable)

데이터가 수천 건 이상일 때 이를 한 페이지에 모두 보여주는 것은 성능과 사용자 경험 측면에서 좋지 않습니다. 스프링 데이터 JPA가 제공하는 Pageable 인터페이스를 사용하면 매우 간단하게 페이징과 정렬을 구현할 수 있습니다.

1. Pageable과 Page 인터페이스

스프링 데이터 JPA는 페이징 처리를 위해 두 가지 핵심 인터페이스를 제공합니다.

  • Pageable: 페이징 요청 정보(페이지 번호, 페이지 크기, 정렬 조건)를 담는 인터페이스입니다.
  • Page<T>: 페이징 결과 데이터뿐만 아니라 전체 페이지 수, 전체 데이터 수 등 부가 정보를 함께 담는 인터페이스입니다.

2. Repository 계층 구현

레포지토리에 Pageable 파라미터를 추가하기만 하면 됩니다.

public interface MemberRepository extends JpaRepository<Member, Long> {

// 이름으로 검색하며 페이징 처리
Page<Member> findByNameContaining(String name, Pageable pageable);
}

3. Controller 계층 구현

컨트롤러에서 Pageable을 매개변수로 받으면 스프링이 쿼리 파라미터(?page=0&size=10&sort=id,desc)를 자동으로 바인딩해 줍니다.

@RestController
@RequestMapping("/api/members")
public class MemberController {

private final MemberRepository memberRepository;

@GetMapping
public Page<MemberResponseDto> getMembers(
@PageableDefault(size = 10, sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {

return memberRepository.findAll(pageable)
.map(MemberResponseDto::from); // Entity를 DTO로 변환
}
}

주요 쿼리 파라미터

  • page: 페이지 번호 (0부터 시작)
  • size: 한 페이지당 데이터 개수
  • sort: 정렬 기준 필드 및 방향 (sort=name,desc)

4. 응답 구조 이해

Page<T> 타입으로 반환하면 다음과 같은 풍부한 메타데이터가 JSON에 포함됩니다.

{
"content": [...], // 실제 데이터 리스트
"pageable": { ... }, // 페이징 정보
"totalElements": 105, // 전체 데이터 개수
"totalPages": 11, // 전체 페이지 수
"last": false, // 마지막 페이지 여부
"size": 10, // 페이지당 개수
"number": 0, // 현재 페이지 번호
"sort": { ... }, // 정렬 정보
"numberOfElements": 10, // 현재 페이지 데이터 개수
"first": true, // 첫 페이지 여부
"empty": false // 데이터 존재 여부
}

5. Page vs Slice

  • Page<T>: 전체 개수를 파악하기 위해 count 쿼리가 추가로 실행됩니다. (게시판 형태에 적합)
  • Slice<T>: 다음 페이지 존재 여부만 확인합니다. count 쿼리가 나가지 않아 성능이 더 좋습니다. (무한 스크롤 형태에 적합)

실무에서는 전체 데이터 개수가 아주 많을 경우 count 쿼리 자체가 성능 부하를 줄 수 있습니다. 이때는 무한 스크롤(Slice) 방식이나 Querydsl을 이용한 카운트 쿼리 최적화 기법을 사용합니다.

Advertisement