5. 반환타입
JPA는 유연환 반환 타입을 지원한다.
//컬렉션 -> 데이터가 없으면 빈 컬렉션
List<Member> findByUsername(String name);
//단건 -> 데이터가 없으면 null
Member findByUsername(String name);
//단건 -> Optional 처리
Optional<Member> findByUsername(String name);
- Member findByUsername(String name); 에서 반환값이 2개라면 예외발생 -> norrectResultSizeDataAccessException
- JPA Exception은 스프링 Exception으로 변환된다.
JPA를 사용하는 클라이언트 입장에서 동일하게 Exception 처리를 할 수 있다.
- 반환 타입은 굉장히 다양함 (공식문서 참고)
6. 페이징과 정렬
페이징과 정렬 파라미터
- org.springframework.data.domain.Sort : 정렬 기능
- org.springframework.data.domain.Pageable : 페이징 기능 (내부에 Sort 포함)
특별한 반환타입
- org.springframework.data.domain.Page: count 쿼리 결과를 포함하는 페이징
- org.springframework.data.domain.Slice : count 쿼리 없이 다음 페이지만 확인 가능
내부적으로 limit +1 조회해서 hasNext()로 다음 페이지가 있는지 알 수 있다.
- List (자바컬렉션) : 결과만 반환
쿼리가 복잡해지면 Paging 사용 지양
실무에서 중요한 내용인데, 쿼리가 조금 복잡해지면 Paging 사용을 지양해야한다.
그 이유는 total를 구하는 성능이 좋지않아서 그런건데, 특히 join의 경우 join해서 나온 결과값의 Total을 구하기 위해서
total을 구하는 query에 또 join을 쓰기때문이다. 그래서 JPA는 count 쿼리를 분리할 수 있는 기능을 제공한다.
sorting 조건이 복잡해지면 JPQL 사용
Sorting도 조건이 복잡해지면 기본으로 제공되는 sort 으로 안되는 경우가 있다. 그럴때는 그냥 JPQL을 사용하면 된다.
// JPA (여기엔 없지만 totalPage, 최초 및 마지막 페이지등을 구해야함.)
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)
.setSingleResult();
}
// Spring Data JPA
@Query(value = "select m from Member m left join m.team t",
countQuery = "select count(m.username) from Member m") // count query 분리
Page<Member> findByAge(int age, Pageable pageable);
// 테스트 코드
@Test
void pagingTest(){
//given
memberRepository.save(new Member("member1", 10));
memberRepository.save(new Member("member2", 10));
int age = 10;
PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username"));
//when
// List<Member>, Slice<Member>로 받아도 된다.
Page<Member> page = memberRepository.findByAge(age, pageRequest);
//then
List<Member> content = page.getContent();
long totalElements = page.getTotalElements();
for (Member member : content) {
System.out.println("member = " + member);
}
System.out.println("totalElements = " + totalElements);
// 참고로 Slice<Member> 슬라이스는 전체갯수, 전체페이지를 가져올 수 없음
assertThat(content.size()).isEqualTo(3); // 갯수
assertThat(page.getTotalElements()).isEqualTo(5); // Page는 count 쿼리 포함하니, total 갯수도 알 수 있음
assertThat(page.getNumber()).isEqualTo(0); // 현재 페이지
assertThat(page.getTotalPages()).isEqualTo(2); // 총 페이지
assertThat(page.isFirst()).isTrue();
assertThat(page.isLast()).isFalse();
assertThat(page.hasNext()).isTrue();
}
'Spring Data JPA' 카테고리의 다른 글
Spring Data JPA - 쿼리 메서드(3) (0) | 2023.04.13 |
---|---|
Spring Data JPA - 쿼리 메서드(1) (0) | 2023.04.12 |
댓글