본문 바로가기

Spring Data JPA

3월 22일 SpringDataJPA 페이징과 정렬

SpringDataJPA 페이징과 정렬

 

순수 JPA 페이징과 정렬 

예제 조건

검색조건 , 나이가 10살,

정렬조건 , 이름으로 내림차순

페이징조건 , 첫번째페이지 , 페이지량을 보여줄 데이터 3건

 

Repository

public List<Member> findByPage(int age , int offset , int limit){

 return em.createQuery(

 "select m from Member m where m.age = :age" +

 " orderBy m.username desc")

.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(); //값을 하나만 받을거라 getSingleResult 를 사용

}

 

스프링 데이터 JPA를 사용한 페이징과 정렬 (기가막힘)

페이징과 정렬 파라미터

org.springframework.data.domain.Sort //정렬가능

org.springframework.data.domain.Pageable //페이징기능 , 내부에 Sort 포함

//위 기능은 JPA 의 기능이 아니라 Spring Data의 기능

 

스프링 데이터 JPA에서의 특별한 반환타입

org.springframework.data.domain.page //totalCount 를 필요로 하는 페이징

org.springframework.data.domain.Slice //totalCount가 필요없는 페이징 ( 모바일 더보기 같은 스타일)

 

위 반환타입을 사용하면 추가직언 Count쿼리없이 다음페이지만 확인가능(내부적으로 limit +1 조회)

List(자바 컬렉션) 추가 : count쿼리 없이 결과만반환.

 

Repository

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

1.반환타입은 page , slice , list 중 하나로 설정한다.

2.매개변수는 꼭 Pageable을 요구한다.

3.따로 메소드 구현은 필요없다.

 

실행단계

1.pageable 을 꼭 생성한다 , 페이지 조건

PageRequest pageRequest = pageRequest.of(0,3,sortBy(sort.Direction,desc,"username"))

//pageRequest.of(최초 페이지,한페이지당 갯수,sortBy(정렬방법 , 정렬기준))

 

Page<Member> page = MemberRepositroy.findByAge(age.pageRequest)

반환 타입이 page일 경우 totalCount도 알아서 구해오게 된다.

개발자가 totalCount를 따로 구할 필요가 없다.

 

List<member> content = page.getContent()

받아온 데이터를 iterator로 확인이 가능하다.

 

page반환 타입으로 값을 가져올 경우 아래 기능들을 사용할 수 있다.

content.size() 반환값을 list에 넣어 size로 확인이 가능하다

 

page.getTotalElements() //모든 데이터수

page.getNumber() // 현재 페이지 번호

page.getTotalPages() //전체 페이지 갯수

page.isFirst() //첫번째 페이지 인지 확인

page.hasNext() //다음페이지가 있는지 확인

 

slice 반환타입일 경우

slice는 모바일 디바이스를 등에서 많이 사용한다, 더보기 기능 사용시 사용

가져오고자 하는갯수에 +1개 만큼 더 가져온다.

slice는 전체 카운터를 가져오지 않는다.

나머지는 page와 동일

 

List 반환타입도 가능은 하지만 별다른 기능은 없다.

 

TotalCount가 결국 DB 전체 count를 종합해야 해서 성능저하의 원인이다.

그래서 countQuery를 page 반환타입에서 분리가 가능하다.

 

*실무에서 중요

@Query(value = "select m from Member m left join m.team t" , countQuery = "select count(m) from Member m")

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

원래 countQuery는 value와 동일한 쿼리에서 count만 구하는데

@Query를 사용해서 검색부 쿼리와 countQuery를 분리해줄수 있다.

 

실무 꿀팁

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

이 결과값은 Entity이기 때문에 API의 반환값으로 반환하면 큰일난다.

이걸 DTO로 변환해야 하는데

Page<MemberDto> toMap = page.map(m -> new MemberDto(m.getId(), m.username(), nul))

stream에 map을 사용해서 손쉽게 DTO로 변환해 줄수 있다,

이 값을 client에게 반환해주면 된다,