스프링 데이터 JPA 페이징과 정렬
페이징과 정렬 파라미터
- org.springframework.data.domain.Sort : 정렬 기능
- org.springframework.data.domain.Pageable : 페이징 기능 (내부에 Sort 포함)
특별한 반환 타입
- org.springframework.data.domain.Page : 추가 count 쿼리 결과를 포함하는 페이징
- org.springframework.data.domain.Slice : 추가 count 쿼리 없이 다음 페이지만 확인 가능
- (내부적으로 limit + 1조회)
- List (자바 컬렉션): 추가 count 쿼리 없이 결과만 반환
repository
public interface MemberRepository extends JpaRepository<Member, Long> {
// 페이징
// @Query(value = "select m from Member m left join m.team t",
// countQuery = "select count(m) from Member m")
Page<Member> findByAge(int age, Pageable pageable);
}
쿼리가 단순할 때는 @Query 없이 그냥 쓰지만 쿼리가 복잡해지면 count 쿼리를 분리를 해줄 수 있다 (성능테스트 해보고)
아래 테스트 코드에 Sort.by 사용 헀는데 sort도 복잡해지면 @Query에서 sort문 넣어서 처리해줘야 한다.
테스트
// 페에징 테스트
@Test
public void paging() throws Exception {
//given
memberRepository.save(new Member("member1", 10));
memberRepository.save(new Member("member2", 10));
memberRepository.save(new Member("member3", 10));
memberRepository.save(new Member("member4", 10));
memberRepository.save(new Member("member5", 10));
int age = 10;
// sort 조건 뺄 수 있다.
PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username"));
//when
Page<Member> page = memberRepository.findByAge(age, pageRequest);
// Page<Member> page = memberRepository.findTop3ByAge(age); 3건만 조회하고 싶을 때, pageRequest 안넘겨도 된다
//dto를 쉽게 반환하는 법
Page<MemberDto> pageDto = page.map(member -> new MemberDto(member.getId(), member.getUsername(), null));
//then
List<Member> content = page.getContent();
long totalElements = page.getTotalElements();
for (Member member: content) {
System.out.println("member = " + member);
}
System.out.println("totalElements = " + totalElements);
assertThat(content.size()).isEqualTo(3); //조회된 데이터 수
assertThat(page.getTotalElements()).isEqualTo(5); //전체 데이터 수
assertThat(page.getNumber()).isEqualTo(0); //페이지 번호
assertThat(page.getTotalPages()).isEqualTo(2); //전체 페이지 번호
assertThat(page.isFirst()).isTrue(); //첫번째 항목인가?
assertThat(page.hasNext()).isTrue(); //다음 페이지가 있는가?
}
PageRequest 생성자의 첫 번째 파라미터에는 현재 페이지를, 두 번째 파라미터에는 조회할 데이터 수를 입력한다.
여기에 추가로 정렬 정보도 파라미터로 사용할 수 있다. 참고로 페이지는 0부터 시작한다.
> 주의: Page는 1부터 시작이 아니라 0부터 시작이다.
paging 쿼리 동작
totalCount 쿼리 자동으로 돌려줌 (실무 - 데이터가 많이질수록 성능 문제가 생길 수 있음
출력 값
dto 반환법
//dto를 쉽게 반환하는 법
Page<MemberDto> toMap = page.map(member -> new MemberDto(member.getId(), member.getUsername(), null));
실습
Page
Slice (count X) 추가로 limit + 1을 조회한다. 그래서 다음 페이지 여부 확인(최근 모바일 리스트 생각해보면 됨)
List (count X)
카운트 쿼리 분리(이건 복잡한 sql에서 사용, 데이터는 left join, 카운트는 left join 안해도 됨)
실무에서 매우 중요!!!
> 참고: 전체 count 쿼리는 매우 무겁다.
public interface Slice<T> extends Streamable<T> {
int getNumber(); //현재 페이지
int getSize(); //페이지 크기
int getNumberOfElements(); //현재 페이지에 나올 데이터 수
List<T> getContent(); //조회된 데이터
boolean hasContent(); //조회된 데이터 존재 여부
Sort getSort(); //정렬 정보
boolean isFirst(); //현재 페이지가 첫 페이지 인지 여부
boolean isLast(); //현재 페이지가 마지막 페이지 인지 여부
boolean hasNext(); //다음 페이지 여부
boolean hasPrevious(); //이전 페이지 여부
Pageable getPageable(); //페이지 요청 정보
Pageable nextPageable(); //다음 페이지 객체
Pageable previousPageable();//이전 페이지 객체
<U> Slice<U> map(Function<? super T, ? extends U> converter); //변환기
}
'프로그래밍 > SpringDataJPA' 카테고리의 다른 글
Spring Data Jpa - @EntityGraph (JPA - PetchJoin) (0) | 2022.06.19 |
---|---|
벌크성 수정 쿼리 (0) | 2022.06.18 |
순수 JPA 페이징과 정렬 (0) | 2022.06.18 |
반환 타입 (0) | 2022.06.18 |
Logging 설정 (0) | 2022.06.18 |