내일배움캠프 Spring 52일차(금) TIL - JPA 페이징

Skadi·2024년 3월 8일
0

1. Paging Repository

  • JpaRepository 의존성
    - ListPagingAndSortingRepository
    - PagingAndSortingRepository : 여기에서 페이징 & 소팅 기능을 제공합니다.

1-1 페이징 처리 프로세스

  1. PageRequest 를 사용하여 Pageable에 페이징 정보를 담아 객체화 한다.
  2. Pageable을 JpaRepository가 상속된 인터페이스의 메서드에 T(Entity)와 함꼐 파라미터로 전달한다.
  3. 2번의 메서드의 return 으로 Page<T>가 응답 된다.
  4. 응답된 Page<T>에 담겨진 Page 정보를 바탕으로 로직을 처리하면 된다.

1-2 Pageable

  1. 페이징 제공 요청 인터페이스 : org.springframework.data.domain.Pageable
    pageable.getTotalPages() : 총 페이지 수
    pageable.getTotalElements() : 전체 개수
    pageable.getNumber() : 현재 페이지 번호
    pageable.getSize() : 페이지 당 데이터 개수
    pageable.hasnext() : 다음 페이지 존재 여부
    pageable.isFirst() : 시작페이지 여부
    pageable.getContent(), PageRequest.get() : 실제 컨텐츠를 가지고 오는 메서드. getContext는 List<Entity> 반환, get()Stream<Entity> 반환
  2. 페이징 제공 응답 인터페이스 : org.springframework.data.domain.Page
    {
        "content": [
            {"id": 1, "username": "User 0", "address": "Korea", "age": 0},
            ...
            {"id": 5, "username": "User 4", "address": "Korea", "age": 4}
        ],
        "pageable": {
            "sort": {
                "sorted": false, // 정렬 상태
                "unsorted": true,
                "empty": true
            },
            "pageSize": 5, // 페이지 크기
            "pageNumber": 0, // 페이지 번호 (0번 부터 시작)
            "offset": 0, // 해당 페이지의 첫번째 요소의 전체 순번 (다음 페이지에서는 5)
            "paged": true,
            "unpaged": false
        },
        "totalPages": 20, // 페이지로 제공되는 총 페이지 수
        "totalElements": 100, // 모든 페이지에 존재하는 총 원소 수
        "last": false,  // 마지막 페이지 여부
        "number": 0,
        "sort": {
            "sorted": false,    // 정렬 사용 여부
            "unsorted": true,
            "empty": true
        },
        "size": 5,       // Contents 사이즈
        "numberOfElements": 5,  // Contents 의 원소 수
        "first": true,   // 첫페이지 여부
        "empty": false   // 공백 여부
    }

1-3 페이지 반환 타입

Page 타입

  • Page 타입은 페이지네이션을 위해 설계된 인터페이스입니다. 이를 사용하면 현재 페이지의 데이터 뿐만 아니라, 전체 데이터 수(totalElements), 전체 페이지 수(totalPages), 현재 페이지 번호, 페이지당 데이터 수 등의 추가 정보를 함께 제공받을 수 있습니다.
  • Page는 게시판 형태의 페이징 처리에 적합하며, 사용자가 특정 페이지로 직접 이동하거나, 전체 데이터의 개수를 알아야 하는 경우 유용합니다.
  • Page를 사용하면 내부적으로 전체 요소의 수를 알아내기 위한 count 쿼리가 실행됩니다. 따라서 데이터의 전체 개수를 알아야 하는 상황에서 효과적입니다.

Slice 타입

  • Slice 타입은 Page와 유사하지만, 전체 페이지 수나 전체 요소의 수를 조회하지 않습니다. 대신, 요청된 페이지에 이어서 데이터가 더 있는지 여부만을 알려주는 hasNext나 hasPrevious를 통해 다음 페이지 또는 이전 페이지의 존재 여부를 확인할 수 있습니다.
  • Slice는 "더보기" 버튼을 통해 다음 데이터를 불러오는 방식의 페이징 처리에 적합합니다. 이 방식은 사용자가 다음 데이터를 요청할 때마다 추가 데이터를 제공하는 방식으로, 전체 데이터의 크기를 미리 알 필요가 없습니다.
  • Slice 사용 시 count 쿼리가 실행되지 않아, Page에 비해 성능상 이점을 가질 수 있습니다. 하지만 offset과 limit을 사용하는 대신, limit + 1 조회를 통해 다음 페이지의 존재 여부를 확인합니다.

List 타입

  • List 타입은 페이징 처리 없이 데이터의 전체 목록을 조회할 때 사용됩니다. 이는 가장 기본적인 반환 타입으로, 특정 페이지 정보나 전체 요소의 수와 같은 추가적인 정보 없이 단순히 데이터 목록만을 반환합니다.
  • 전체 데이터를 한 번에 불러오기 때문에, 데이터의 양이 많은 경우 성능 저하의 원인이 될 수 있습니다. 따라서 데이터의 양이 적고, 단순히 전체 목록을 조회하는 경우에 적합합니다.
  • List 타입을 사용할 때는 추가적인 페이징 처리를 수동으로 구현해야 할 수도 있습니다. 이는 Page나 Slice와 같이 Spring Data JPA가 제공하는 페이징 처리 기능을 사용하지 않는 경우에 해당합니다.

1-4 정렬

  • Sort 사용
Sort sort1 = Sort.by("name").descending();     // 내림차순
Sort sort2 = Sort.by("password").ascending();  // 오름차순
Sort sortAll = sort1.and(sort2);      // 2개이상 다중정렬도 가능하다
Pageable pageable = PageRequest.of(0, 10, sortAll);  // pageable 생성시 추가
  • 컬럼 값으로 정렬 (@Query 사용시 Alias(쿼리에서 as 로 지정한 문구) 를 기준으로 정렬할 수 있다.)
// 아래와 같이 AS user_password 로 Alias(AS) 를 걸어주면
@Query("SELECT u, u.password AS user_password FROM user u WHERE u.username = ?1")
List<User> findByUsername(String username, Sort sort);
  
---
  
// 이렇게 해당 user_password 를 기준으로 정렬할 수 있다.
List<User> users = findByUsername("user", Sort.by("user_password"));
  • SQL 함수를 사용해서 정렬하기 (JpaSort 를 사용해서 쿼리 함수를 기준으로 정렬할 수 있다.)
// 아래와 같이 일반적인 쿼리에서
@Query("SELECT u FROM user u WHERE u.username = ?1") // 이건 없어도됨
List<User> findByUsername(String username, Sort sort);
  
---
  
// 이렇게 쿼리함수 LENGTH() 조건을 걸어서 password 문자길이 기준으로 정렬할 수 있다.
List<User> users = findByUsername("user", JpaSort.unsafe("LENGTH(password)"));

0개의 댓글