JPA 페이징

zwon·2023년 10월 8일
0

JPA

목록 보기
9/9

SW 직무 역량 부트캠프를 수강했을 때 진행한 팀 프로젝트에서 페이징 기능 구현에 실패했다.
그래서 페이징에 대한 내용을 진짜 공부하고싶었는데 공부한 부분을 정리하겠다.

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();
  }
  • 테스트 코드
@Test
  public void paging() {
    Member m1 = new Member("member1", 10);
    Member m2 = new Member("member2", 10);
    Member m3 = new Member("member3", 10);
    Member m4 = new Member("member4", 20);
    Member m5 = new Member("member5", 25);

    memberJpaRepository.save(m1);
    memberJpaRepository.save(m2);
    memberJpaRepository.save(m3);
    memberJpaRepository.save(m4);
    memberJpaRepository.save(m5);

    int age = 10;
    int offset = 0;
    int limit = 3;

    List<Member> result = memberJpaRepository.findByPage(age, offset, limit);
    long totalCount = memberJpaRepository.totalCount(age);

    Assertions.assertThat(result.size()).isEqualTo(3);
    Assertions.assertThat(totalCount).isEqualTo(3);
  }
  • 사실 좀 빠진 부분이 있는데 totalCount를 활용해서 현재 페이지 수를 구해야하고,, 마지막 페이지가 있는지, 첫번 째 페이지인지 아닌지 등 좀 고려해야할 부분들이 있는데 Spring Data JPA에서는 이러한 부분들을 알아서 계산해준다.

코드를 봐보자.


Spring Data JPA 페이징 코드

  • 페이징을 인터페이스로 표준화 시킴.

[Page 예시 코드 - 나이를 기준으로 검색]

public interface MemberRepository extends JpaRepository<Member, Long> {
	// pageable에는 쿼리 조건들을 넣으면 됨.
    Page<Member> findByAge(int age, Pageable pageable); 
  }
  @Test
  public void paging() {
    Member m1 = new Member("member1", 10);
    Member m2 = new Member("member2", 10);
    Member m3 = new Member("member3", 10);
    Member m4 = new Member("member4", 10);
    Member m5 = new Member("member5", 10);

    memberRepository.save(m1);
    memberRepository.save(m2);
    memberRepository.save(m3);
    memberRepository.save(m4);
    memberRepository.save(m5);

    // page0에서 3개 가져와, sorting 조건은 username을 기준으로 내림차순이야.
    PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username"));
    
    // pageRequest은 Pagable 인터페이스의 구현체
    Page<Member> page = memberRepository.findByAge(10, pageRequest);
    
    // 반환타입이 page면 totalCount 쿼리까지 함꼐 날림!
    // 왜냐하면 페이지 계산하기 위해 필요하니까 알아서 날린거임!
    Page<Member> content = page.getContent();

    // totalCount 가져오는 메서드
    long totalElements = page.getTotalElements();

    for (Member member : content) {
      System.out.println("member = " + member);
    }
    System.out.println("totalElements = " + totalElements);

    Assertions.assertThat(content.size()).isEqualTo(3);
    Assertions.assertThat(page.getTotalElements()).isEqualTo(5);
    Assertions.assertThat(page.getNumber()).isEqualTo(0);
    Assertions.assertThat(page.getTotalPages()).isEqualTo(2);
    Assertions.assertThat(page.isFirst()).isTrue();
    Assertions.assertThat(page.hasNext()).isTrue();

  }
  • 페이징 관련한 코드는 주석으로 설명을 달아놨다.
  • agable의 인터페이스의 구현체인 PageRequest를 사용한다.
  • PageRequest 생성자의 첫 번째 파라미터에는 현재 페이지, 두 번째 파라미터는 조회할 데이터 수, 세 번째 파라미터에는 추가로 정렬 조건을 작성할 수 있다.
  • 그리고 반환타입으로 Page<...>, Slice<...>, List<...>가 있다.
    • Page<...> : totalCount 쿼리 결과를 포함 + content 쿼리
    • Slice<...> : totalCount 쿼리 결과 포함X + content 쿼리 + 다음 페이지만 확인 (limit + 1와서 확인함.)
    • List<...> : totalCount 쿼리 없이 List 쿼리만 나감.
    • 직접 날려보면서 DB로 나가는 쿼리를 눈으로 확인하는 것을 추천한다.
  • 참고로 페이징 시작은 1부터가 아닌 0부터다.

인프런 - 실전! 스프링 데이터 JPA를 수강하면서 정리한 글입니다.

profile
Backend 관련 지식을 정리하는 Back과사전

0개의 댓글