[JPA] 데이터 JPA(2)
본 포스트는 Inflearn
의 김영한님 강의를 바탕으로 작성했습니다.
Paging 이슈
JPA가 없던 시절에 Paging 처리를 하는 것은 굉장히 귀찮은 일이었다. JPA가 등장하면서 Paging을 쉽게 처리할 수 있게 되었다. Spring data JPA를 사용하면 페이지 계산과 같이 반복적이고 실수하기 쉬운 것을 추상화해서 사용하기 쉽게 제공해준다.
먼저 순수 JPA를 사용한 Paging 처리를 보고 다음으로 Spring data JPA를 사용해서 처리하는 코드를 살펴보자.
순수 JPA Paging
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)
.setMaxResult(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();
}
offset과 limit을 받아서 JPQL을 짜면 된다. 결과값의 개수를 알아야 하기 때문에 별도의 CountQuery 도 날려줘야 한다.
그럼 이제 Spring data JPA를 사용할 때의 Paging을 살펴보자.
Page<Member> findByUsername(String name, Pageable pageable);
Slice<Member> findByUsername(String name, Pageable pageable);
List<Member> findByUsername(String name, Pageable pageable);
List<Member> findByUsername(String name, Sort sort);
먼저 반환타입에 따른 동작방식을 이해해보자.
Page
객체를 반환하는 경우 Spring data JPA 가 별도로 CountQuery를 생성해서 날려준다.
Slice
객체를 반환하는 경우에는 별도의 CountQuery가 날라가지 않는다. 대신에 Pageable에서 받은 개수보다 1개 더 많이 가져와서 뒤에 페이지가 더 존재하는지 확인한다. 이제 Page 객체와 Slice 객체의 내부를 살펴보자 :)
Page Interface
public interface Page<T> extends Slice<T> {
int getTotalPages();
long getTotalElements();
<U> Page<U> map(Fuction<? supter T, extends U> converter);
}
Slice Interface
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);
}
이런 기능들을 예전에는 한땀한땀 열심히 구현해서 사용해야 했었다. 그런데 JPA에서 이미 다 제공해주기 때문에 그냥 가져다 사용하면 된다.
여기서 두가지 주의해야 할 점이있다. JPA의 페이지는 1부터가 아니라 0부터 시작한다는 것이다. 두번째는 CountQuery는 무거운 연산이라는 것이다. 때문에 복잡한 쿼리에서는 CountQuery를 분리하고 left join같은 경우는 CountQuery를 할 필요가 없다. 이를 주의하자!
참고 사이트 출처
- https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-%EC%8B%A4%EC%A0%84
더 자세한 내용은 김영한님 강의를 참고하자!