Spring/Spring Data JPA
Spring Data JPA - 페이징과 정렬
jddng
2022. 3. 20. 18:43
728x90
반응형
페이징과 정렬
- 순수 JPA 페이징과 정렬
- 스프링 데이터 JPA 페이징과 정렬
순수 JPA의 페이징과 정렬
public List<Member> findByPage(int age, int offset, int limit) {
return em.createQuery("select m from Member m where m.age = :age order by m.username desc", Member.class)
.setParameter("age", age)
.setFirstResult(offset)
.setMaxResults(limit)
.getResultList();
}
public long totalCount(int age) {
return em.createQuery("select count(m) from Member m where m.age = :age", Long.class)
.setParameter("age", age)
.getSingleResult();
}
스프링 데이터 JPA의 페이징과 정렬
- 페이징과 정렬 파라미터
- Sort : 정렬 기능
- Pageable : 페이징 기능(내부에 Sort 포함), 구현체로 PageRequest 사용 - 특별한 반환 타입
- Page : count 쿼리 결과를 포함하는 페이징
- Slice : count 쿼리 없이 다음 페이지만 확인 가능(내부적으로 limit + 1 조회)
- List : count 쿼리 없이 결과만 반환 - 주의: Page는 1부터 시작이 아니라 0부터 시작이다.
Page<Member> findByUsername(String name, Pageable pageable); //count 쿼리 사용
Slice<Member> findByUsername(String name, Pageable pageable); //count 쿼리 사용 안함
List<Member> findByUsername(String name, Pageable pageable); //count 쿼리 사용 안함
List<Member> findByUsername(String name, Sort sort);
테스트 코드
@Test
public void page() 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));
//when
PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username"));
Page<Member> page = memberRepository.findByAge(10, pageRequest);
//then
List<Member> content = page.getContent(); //조회된 데이터
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(); //다음 페이지가 있는가?
}
Page 인터페이스
public interface Page<T> extends Slice<T> {
int getTotalPages(); //전체 페이지 수
long getTotalElements(); //전체 데이터 수
<U> Page<U> map(Function<? super T, ? extends U> converter); //변환기
}
Slice 인터페이스
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); //변환기
}
count 쿼리
- count 쿼리 때문에 성능이 안 좋아질 수 있으므로 count 쿼리를 따로 작성할 수 있다.
- 카운트 쿼리 분리(이건 복잡한 sql에서 사용, 데이터는 left join, 카운트는 left join 안 해도 됨)
@Query(value = “select m from Member m”,
countQuery = “select count(m.username) from Member m”)
Page<Member> findMemberAllCountBy(Pageable pageable);
페이징을 유지하면서 Entity를 DTO로 변환하기
- Page의 map 메서드를 이용하여 DTO를 변환한 후 페이징을 유지하여 새로운 Page를 반환할 수 있다.
Page<Member> page = memberRepository.findByAge(10, pageRequest);
Page<MemberDto> dtoPage = page.map(m -> new MemberDto());
728x90
반응형