ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Data JPA - 페이징과 정렬
    Spring/Spring Data JPA 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
    반응형

    댓글

Designed by Tistory.