SpringDataJPA

페이징처리 간편기능

lby132 2022. 11. 29. 23:06

!!SpringDataJpa에서 제공하는 페이징 처리를 할때 첫번째는 0부터 시작한다.

   @Test
    void paging() {
        //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;
        //이름순으로 정렬된 값을 가져옴 첫번째 파라미터는 페이지번호, 두번째 파라미터는 사이즈
        final PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username"));

        //when
        //반환 타입이 Page면 totalCount쿼리까지 같이 날린다.
        final Page<Member> page = memberRepository.findByAge(age, pageRequest);

        //일반적인 페이징처리방법. 데이터가 뒤에 더있고 상관없이 내가 정한 갯수만큼만 페이징처리함
        List<Member> page1 = memberRepository.findByAge1(age, pageRequest);

        //반환 타입이 Slice totalCount를 날리지 않는다.
        Slice<Member> page2 = memberRepository.findByAge2(age, pageRequest);
        
        //then 
        final List<Member> content = page.getContent();
        final long totalElements = page.getTotalElements();
        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();

        //Slice는 토탈카운트를 제공하지 않는다. 그리고 페이징 사이즈도 내가 정한것에 +1을 해서 보내줌. (모바일 환경에서 더보기 버튼 같은 기능제공)
        assertThat(content.size()).isEqualTo(3);
        assertThat(page2.getNumber()).isEqualTo(0);
        assertThat(page2.isFirst()).isTrue();
        assertThat(page2.hasNext()).isTrue();

    }

인터페이스

Page<Member> findByAge(int age, Pageable pageable);

List<Member> findByAge1(int age, Pageable pageable);

Slice<Member> findByAge2(int age, Pageable pageable);

페이징처리에 매우 편리한 기능을 제공한다. 

그런데 만약 복잡한 쿼리를 쓸때 카운트쿼리가 섞여있으면 성능에 매우 안좋다고 한다. 카운트쿼리는 그냥 불러오기만하면 되는데 괜히 섞여있어서 조인이 일어날때 쓸때없이 카운트쿼리까지 가져오고 하는건 별로인가보다.

@Query(value = "select m from Member m left join m.team t",
        countQuery = "select count(m) from Member m")
List<Member> findByAge1(int age, Pageable pageable);

 

그래서 이런식으로 카운트쿼리만 따로 분리할 수 있다.

그런데 

final Page<Member> page = memberRepository.findByAge(age, pageRequest);

이상태로 responseBody로 내보내면 위험하니까 (엔티티보단 Dto로 변환해서 내보내는게 안전하고 좋다.) 그것까지도 Page가 제공해준다.

responseBody로 내보내기 위해 Page는 map()이라는 메소드를 제공한다.

final Page<MemberDto> toMap = page.map(m -> new MemberDto(m.getId(), m.getUsername(), null));

 

뭐 stream.map()을 이용해도 될것 같은데 아무튼 더 편리하게 사용할 수 있는것 같다.

 

 

 

 

'SpringDataJPA' 카테고리의 다른 글

Auditing  (1) 2022.12.02
페치조인 정리  (0) 2022.11.30
@Query  (0) 2022.11.29
NamedQuery  (0) 2022.11.29
@EntityGraph  (0) 2022.10.30