- JPA 페이징
- Repository 코드
// 페이징 설정
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")
.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();
}
- JPQL를 작성하고 offset, limit를 파라미터로 넘겨 FirstResult, MaxResult를 통해 페이징을 하는 과정이다.
- 위의 과정을 통해 해당 페이지에 있는 엔티티들을 List에 담아 반환한다.
- Test 코드
@Test
public void paging() {
//given
memberJpaRepository.save(new Member("member1", 10));
memberJpaRepository.save(new Member("member2", 10));
memberJpaRepository.save(new Member("member3", 10));
memberJpaRepository.save(new Member("member4", 10));
memberJpaRepository.save(new Member("member5", 10));
int age = 10;
int offset = 0;
int limit = 3;
//when
List<Member> members = memberJpaRepository.findByPage(age, offset, limit);
long totalCount = memberJpaRepository.totalCount(age);
//then
assertThat(members.size()).isEqualTo(3);
assertThat(totalCount).isEqualTo(5);
}
- member 객체 조회 및 DB 방언에 의해 h2 DB에 맞게 페이징 및 정렬까지 실행하였다.
- count 조건에 맞춰서 쿼리를 실행 한 것도 확인할 수 있다.
- 위에서 작성한 코드들이 정상적으로 동작하는 것을 확인 할 수 있다.
- 스프링 데이터 JPA 페이징과 정렬
- 페이징과 정렬 파라미터
1. org.springframework.data.domain.Sort : 정렬 기능
2. org.springframework.data.domain.Pageable : 페이징 기능 (내부에 Sort 포함)
- 특별한 반환 타입
1. org.springframework.data.domain.Page : 추가 count 쿼리 결과를 포함하는 페이징
2. org.springframework.data.domain.Slice : 추가 count 쿼리 없이 다음 페이지만 확인 가능(내부적 으로 limit + 1조회)
3. List (자바 컬렉션): 추가 count 쿼리 없이 결과만 반환
- 페이징과 정렬 사용 예제
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);
- 조건
1. 검색 조건 : 나이 10살
2. 정렬 조건 : 이름으로 내림차순
3. 페이징 조건 : 첫 번째 페이지, 페이지당 보여줄 데이터는 3건
- 스프링 데이터 JPA
public interface MemberRepository extends Repository<Member, Long> {
Page<Member> findByAge(int age, Pageable pageable);
}
- Test 코드
//페이징 조건과 정렬 조건 설정
@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(); //다음 페이지가 있는가?
}
- findByAge의 두번째 파라미터로 받은 Pageable은 인터페이스다. PageRequest 객체를 사용하여 해당 인터페이스를 구현한다.
- PageRequest 생성자의 첫 번째 파라미터에는 현재 페이지를, 두 번째 파라미터에는 조회할 데이터 수를 입력한다. 여기에 추가로 정렬 정보도 파라미터로 사용할 수 있다. (페이지는 0부터 시작한다.)
- Page 인터페이스는 Slice를 대부분 지원한다.
- Page의 경우 Count까지 알아서 실행하는데,
//페이징 + count 쿼리 분리
@Query(value = "select m from Member m left join m.team t", // join만 하면 count 쿼리도 join을 한다.
countQuery = "select count(m.username) from Member m") //count 쿼리를 분리하면 count 쿼리에는 join을 하지 않는다.
Page<Member> findByAge(int age, Pageable pageable);
@Query(value = "select m from Member m left join m.team t"
- 이 부분만 삭정하고 JPQL을 실행하게 되면
- count 쿼리가 실행됨과 동시에 join까지 실행하게 된다. 이렇게 되면 데이터의 양이 많아지게 되면 Count하는 양도 많아져 성능에 영향을 줄 수 있다.
@Query(value = "select m from Member m left join m.team t", // join만 하면 count 쿼리도 join을 한다.
countQuery = "select count(m.username) from Member m") //count 쿼리를 분리하면 count 쿼리에는 join을 하지 않는다.
- 하지만 countQuery를 작성하여 쿼리를 실행하게 되면,
- count쿼리를 날릴 때 join은 실행하지 않는다.
- 페이지를 유지하면서 엔티티를 DTO로 변환하기
Page<Member> page = memberRepository.findByAge(10, pageRequest);
Page<MemberDto> toMap = page.map(m -> new MemberDto(m.getId(), m.getUsername(), null));
- map을 통해서 member 객체를 DTO로 변환해서 Page에 담아서 반환할 수 있다.
출처 : 인프런 - 김영한(실전! 스프링 데이터 JPA)
'Programming > Spring' 카테고리의 다른 글
Spring Data JPA - @EntityGraph (0) | 2023.07.26 |
---|---|
Spring Data JPA - (벌크성 수정 쿼리) (0) | 2023.07.26 |
Spring Data JPA - 쿼리 메소드 (메소드 이름으로 쿼리 생성, @Query) (0) | 2023.07.24 |
Spring Data JPA - 공통 인터페이스 기능 (0) | 2023.07.24 |
Spring - 스프링 트랜잭션 전파2 - 활용 (0) | 2023.07.08 |