Book Study/스프링 부트 핵심 가이드

08. Spring Data JPA 활용 (2)

정진킴 2023. 11. 7. 19:28

8.4 정렬과 페이징 처리

8.4.1 정렬 처리하기

  • 일반적인 쿼리문에서 정렬을 사용할 때는 ORDER BY 구문을 사용한다.
  • 기본 쿼리 메서드를 작성한 후 OrderBy 키워드를 삽입하고 정렬하고자 하는 컬럼과 오름차순/내림차순을 설정하면 정렬을 수행한다.
// Asc : 오름차순, Desc : 내림차순
List<Product> findByNameOrderByNumberAsc(String name);
List<Product> findByNameOrderByNumberDesc(String name);
-- DESC 쿼리

    select
        product0_.number as number1_0_,
        product0_.created_at as created_2_0_,
        product0_.name as name3_0_,
        product0_.price as price4_0_,
        product0_.stock as stock5_0_,
        product0_.updated_at as updated_6_0_ 
    from
        product product0_ 
    where
        product0_.name=? 
    order by
        product0_.number desc
  • 여러 개 컬럼을 사용하는 정렬 구문 경우 And 또는 Or 를 사용하지 않고 우선순위를 기준으로 작성한다.
// And를 붙히지 않음
List<Product> findByNameOrderByPriceAscStockDesc(String name);
  • 쿼리 메서드 뿐만 아니라 매개변수를 활용하여 쿼리를 작성할 수 있다.
// productRepository
List<Product> findByName(String name, Sort sort);

// service
productRepository.findByName("펜", Sort.by(Order.asc("price")));
productRepository.findByName("펜", Sort.by(Order.asc("price"), Order.desc("stock")));

// sort 가 많은 경우 메서드로 분리하여 호출 가능
productRepository.findByName("펜", getSort());

private Sort getSort() {
	return Sort.by(
    	Order.asc("price"),
        Order.desc("stock")
    );
}

8.4.2 페이징 처리

  • JPA 에서는 이 같이 페이징 처리를 위해 PagePageable을 사용한다.
  • 아래 소스는 Page 처리를 위한 쿼리 메서드 예시이다.
Page<Product> findByName(String name, Pageable pageable);
  • 메서드를 호출할 때 리턴 타입으로 Page 객체를 받아야 하기 때문에 Page<Product>로 타입을 선언해서 리턴을 받는다.
  • Pageable 파라미터를 전달하기 위해 PageRequest 클래스를 사용
    • PageRequest는 Pageable 구현체이다.
Page<Product> productPage = productRepository.findByName("펜", PageRequest.of(0,2));
of 메서드 매개변수 설명 비고
of(int page, int size) 페이지 번호(0부터 시작), 페이지당 데이터 개수

페이지 번호가 1이면 쿼리에 offset 이 들어감
데이터를 정렬하지 않음
of(int page, int size, Sort) 페이지 번호, 페이지당 데이터 개수, 정렬 sort에 의해 정렬
of(int page, int size, Direction, String... properties) 페이지 번호, 페이지당 데이터 개수, 정렬 방향, 속성(컬럼) Sort.by(direction, properties)에 의해 정렬
  • 각 페이지를 구성하는 세부적인 값을 보려면 getContent() 를 호출 후 출력하면 배열 형태로 값이 출력된다.
Page<Product> productPage = productRepository.findByName("펜", PageRequest.of(0,2));
System.out.println(productPage.getContent());

8.5 @Query 어노테이션 사용하기

  • 쿼리 메서드를 생성 할 수도 있지만 @Query 어노테이션을 사용해 직접 JPQL을 작성할 수도 있다.
  • 만약 데이터베이스를 다른 데이터베이스로 변경할 일이 없다면 직접 해당 데이터베이스에 특화된 SQL을 작성할 수 있으며, 주로 튜닝된 쿼리를 사용하고자 할 때 직접 SQL을 작성한다.
@Query("SELECT p FROM Product p WHERE p.name = ?1")
List<Product> findByName(String name);
  • ?1 은 첫번째 파라미터를 의미한다. 하지만 이 같은 방식을 사용할 경우 파라미터의 순서가 바뀌면 오류가 발생할 가능성이 있기 때문에 @Param 어노테이션을 사용하는 것을 추천한다.
@Query("SELECT p FROM Product p WHERE p.name = :name")
List<Product> findByNameParam(@Param("name") String name);
  • @Query를 사용하면 엔티티 타입이 아닌 원하는 컬럼의 값만 추출할 수 있다.
  • 메서드에서는 Object 배열의 리스트 형태로 리턴 타입을 지정해야 한다.
@Query<"SELECT p.name, p.stock FROM Product p WHERE p.name = :name")
List<Object[]> findByNameParam2(@Param("name") String name);