본문 바로가기
Java/ORM

JAVA ORM - Spring Data JPA(페이징, 슬라이스, countQuery)

by 티코딩 2024. 8. 23.

페이징(Paging)

페이징은 데이터를 페이지단위로 나눠 가져오는 기술. Spring data Jpa에서는 'pageable'인터페이스와 'Page' 객체를 사용해 페이징을 처리한다.

public interface UserRepository extends JpaRepository<User, Long> {
    Page<User> findByLastName(String lastName, Pageable pageable);
}

반환타입은 Page 객체, 인자로는 Pageable 객체를 받아야한다.

Pageable pageable = PageRequest.of(0, 10, Sort.by("firstName").ascending());
Page<User> page = userRepository.findByLastName("Smith", pageable);

List<User> users = page.getContent();  // 현재 페이지의 데이터
int totalPages = page.getTotalPages();  // 전체 페이지 수
long totalElements = page.getTotalElements();  // 전체 데이터 수
boolean hasNext = page.hasNext();  // 다음 페이지가 있는지 여부

pageable의 첫번째 인자 0은 페이지 번호를 나타내고, 10은  한 페이지 내에 10개의 데이터를 가져오도록 설정한것이다. 

 

ㅇ 슬라이스(Slice)

슬라이스는 페이징과 유사하지만, 전체 페이지 수나 전체 데이터 수와 같은 메타 데이터를 제공하지 않고, 다음 페이지가 있는지 여부만 확인할 수 있는 기능이다. 슬라이스는 현재 페이지의 데이터와 함께 다음 페이지가 있는지 여부만 제공한다.

슬라이스는 대용량 데이터에서 전체 페이지 수를 계산하는 것이 비용이 클 경우 유용하다. 데이터의 일부만 필요한 경우 페이징보다는 가벼운 슬라이스를 쓰는게 더 좋다.

구현방법도 Paging과 비슷하다.

public interface UserRepository extends JpaRepository<User, Long> {
    Slice<User> findByLastName(String lastName, Pageable pageable);
}

인자에는 똑같이 pageable 객체가 들어가지만 반환타입은 Slice다.

Pageable pageable = PageRequest.of(0, 10, Sort.by("firstName").ascending());
Slice<User> slice = userRepository.findByLastName("Smith", pageable);

List<User> users = slice.getContent();  // 현재 슬라이스의 데이터
boolean hasNext = slice.hasNext();  // 다음 슬라이스가 있는지 여부

전체 데이터 크기나 페이지 수가 필요할 경우, Page 객체를 사용하고, 다음 페이지가 있는지만 확인하면 되는 경우엔 Slice를 사용하는게 좋다.

ㅇ CountQuery

CountQuery는 Spring Data JPA에서 페이징 처리를 할 때, 전체 데이터 수를 계산하는 데 사용되는 개념이다. Page 객체를 반환하는 쿼리를 실행할 때, 전체 페이지 수 같은 데이터 제공하기 위해 전체 데이터의 개수를 계산해야 하는데, 이때 사용된다.

위의 예제에서 findByLastname 메서드가 호출될때, Spring data Jpa는 데이터 조회쿼리, 카운트 쿼리를 실행하게된다.

Spring data Jpa는 기본적으로 countQuery를 자동으로 실행하지만, 복잡한 JPQL쿼리나 네이티브 쿼리에서는 직접 정의해야 할 때가 있다.

public interface UserRepository extends JpaRepository<User, Long> {

    @Query(
        value = "SELECT u FROM User u JOIN u.department d WHERE d.name = :departmentName",
        countQuery = "SELECT COUNT(u) FROM User u JOIN u.department d WHERE d.name = :departmentName"
    )
    Page<User> findByDepartmentName(@Param("departmentName") String departmentName, Pageable pageable);
}

여기서 value쿼리는 페이징된 데이터를 가져오는 JPQL,

countQuery는 전체 데이터 수를 계산하는 쿼리.