![[Spring] Spring Data JPA 페이징 처리 알아보기](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhD1rG%2FbtswaqUQdQg%2FZQy0NUL7JbzqAT21WbWnOK%2Fimg.png)
페이지네이션(Pagination)
데이터베이스에서 특정 정보를 조회할 때, 조회된 데이터가 너무 많으면 사용자의 가독성이 떨어지고, 데이터가 많은 만큼 서버의 부하가 커질 것입니다. 그렇기에 적당한 양의 데이터를 나눠 가져오는 게 좋습니다.
페이지네이션이란 전체 데이터를 지정된 수의 데이터로 나눠 전달하는 과정을 의미합니다. 페이징이라고도 합니다.
Spring Data JPA에서는 Pageable 클래스를 통해 페이징 처리를 간단하게 할 수 있습니다.
Pageable과 PageRequest
Pageable은 페이징 처리에 필요한 정보를 담는 인터페이스입니다.
PageRequest에 의해 Pageable에 페이징 정보가 담겨 객체화됩니다.
Page와 Slice
JpaRepository<>를 상속받은 레포지토리에 Pageable 객체를 전달하면, 반환 타입으로 Slice, Page, List를 받을 수 있습니다. List는 제외하고 Page와 Slice에 대해 알아보겠습니다.
Page는 Slice를 상속받았습니다.
Page는 조회 쿼리 이후 전체 데이터 개수를 한 번 더 조회하는 count 쿼리가 실행되기에 전체 데이터 개수 및 페이지 또한 조회할 수 있습니다.
- getTotalPages(): 전체 페이지 수
- getTotalElements(): 전체 데이터 수
반면, Slice는 전체 페이지 수, 전체 데이터 수 조회가 불가능하고 다음 Slice의 존재 여부만 알 수 있습니다.
그렇기에 모바일과 같이 전체 데이터 수가 필요 없는 환경에서 자주 사용됩니다. (무한 스크롤 등)
또한, count 쿼리를 실행하지 않기에 데이터가 많을수록 성능 면에서 Page에 비해 유리합니다.
Controller
최근 모바일에서는 무한 스크롤 방식을 많이 사용하기에 아래 예시는 Slice를 사용하였습니다.
아래 코드는 page 번호를 파라미터로 받고, 5개씩 조회하고자 합니다.
정렬 방식은 Posts엔티티의 id값을 기준으로 내림차순으로 정렬하고자 합니다.
//Post를 전체 조회하는 코드
@GetMapping("/api/posts")
public ResponseDto findAll(@RequestParam("page") int page) {
Pageable pageable = PageRequest.of(page, 5, Sort.by("id").descending());
return ResponseUtil.SUCCESS("Posts 전체 조회에 성공하였습니다.", postsService.findAllDesc(pageable));
}
- of(int page, int size, Sort sort) : Pageable객체에 페이지 번호와 개수, 정렬 관련 정보를 담을 수 있다.
page번호는 0부터 시작하며, Sort는 생략 가능합니다.
추가적으로 Sort 객체의 경우, 아래와 같은 사용도 가능합니다.
Sort s1 = Sort.by("id").descending();
Sort s2 = Sort.by("modified_date").ascending();
Sort s3 = s1.and(s2);
Pageable pageable = PageRequest.of(page, size, s3);
Service
@Transactional(readOnly = true)
public Slice<PostsResponseDto> findAllDesc(Pageable pageable) {
Slice<Posts> postsSlice = postsRepository.findAllByStatus(pageable, PostsStatus.RECRUITING);
Slice<PostsResponseDto> postsResponseDtos = postsSlice.map(p -> new PostsResponseDto(p, p.getUser().getName(), p.getUser().getProfileImage(), p.getUser().getGender()));
return postsResponseDtos;
}
Service에서는 findAllByStatus를 통해서 가져온 Posts 값들을 PostsResponseDto로 변환시키기 위해 각각 매핑해주는 과정을 추가하였습니다.
Repository
Posts의 상태가 "RECRUTING"인 Posts만 조회하는 쿼리를 작성하였습니다.
pageable에 이미 id를 기준으로 내림차순 한다는 정보가 담겨있기에 따로 쿼리 작성을 하지 않아도 됩니다.
public interface PostsRepository extends JpaRepository<Posts, Long> {
@Query("select p from Posts p where p.status = :status")
Slice<Posts> findAllByStatus(Pageable pageable, @Param("status") PostsStatus recruiting);
}
결과
Postman에서 실행 결과 아래와 같이 페이지에 대한 메타 데이터들을 확인할 수 있습니다.
만약 Slice가 아닌 List로 값을 받는 경우에 위와 같은 메타데이터는 생성되지 않습니다.
'Spring' 카테고리의 다른 글
[Spring] URL 이미지 리사이징 후, S3에 업로드 (3) | 2024.07.28 |
---|---|
[Spring] Google STT(Speech-to-Text) 서비스 사용하기 (2) | 2024.06.30 |
[Spring] Spring Security와 OAuth 2.0으로 구글 소셜 로그인 구현(1) (0) | 2023.08.11 |
JPA, Hibernate, Spring Data JPA? (0) | 2023.08.06 |
[Spring] Build.Gradle 공부하기 (0) | 2023.07.28 |
느리더라도 단단하게 성장하고자 합니다!
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!