정렬과 페이징 처리
애플리케이션에서 자주 사용되는 정렬과 페이징 처리는 쿼리 메서드를 작성하는 방법을 기반으로 수행할 수 있다.
기본 쿼리 메서드를 통해서도 가능하다. 기본적인 정렬과 페이징 처리 방법을 알아보겠습니다.
정렬 처리하기
일반적인 쿼리문에서는 정렬을 사용할 때 ORDER BY 구문을 사용한다.
쿼리 메서드도 정렬 기능에 동일한 키워드가 사용된다.
// Asc : 오름차순, Desc : 내림차순
List<Product> findByOrderByNumberAsc(String name);
List<Product> findByOrderByNumberDesc(String name);
- 기본 쿼리 메서드를 작성한 후에 OrderBy 키워드를 삽입한다.
- 정렬하고자 하는 컬럼과 오름차순/내림차순을 설정하면 정렬이 수행된다.
쿼리 메서드에서 여러 정렬 기준 사용
// And를 붙이지 않는다.
List<Product> findByNameOrderByPriceAscStockDesc(String name);
- Price를 기준으로 오름 차순 정렬한다.
- 후순위로 stock(재고수량)을 기준으로 내림차순 정렬한다.
매개변수를 활용한 쿼리 정렬
// And를 붙이지 않는다.
List<Product> findByName(String name, Sort sort);
- 해당 메서드는 이름에 키워드를 넣지 않고 Sort 객체를 활용한다.
- 매개변수로 받아들인 정렬 기준을 가지고 쿼리문을 작성하게 된다.
코드 정렬 테스트
Sort 객체 테스트 코드 예시
@SpringBootTest
class ProductRepositoryTest {
@Autowired
ProductRepository productRepository;
@Test
void sortingAndPagingTest() {
Product product1 = Product.builder()
.name("pen")
.price(1000)
.stock(100)
.createdAt(LocalDateTime.now())
.updatedAt(LocalDateTime.now())
.build();
Product product2 = Product.builder()
.name("pen")
.price(5000)
.stock(500)
.createdAt(LocalDateTime.now())
.updatedAt(LocalDateTime.now())
.build();
Product product3 = Product.builder()
.name("pen")
.price(500)
.stock(50)
.createdAt(LocalDateTime.now())
.updatedAt(LocalDateTime.now())
.build();
Product savedProduct1 = this.productRepository.save(product1);
Product savedProduct2 = this.productRepository.save(product2);
Product savedProduct3 = this.productRepository.save(product3);
}
}
쿼리 메서드 Sort 객체 전달
productRepository.findByName("pen", Sort.by(Order.asc("price")));
productRepository.findByName("pen", Sort.by(Order.asc("price"), Order.desc("stock")));
- Sort 클래스는 내부 클래스로 정의되어 있는 Order 객체를 활용하여 정렬 기준을 생성한다.
- Order 객체에는 asc와 desc 메서드가 포함되어 있어, 오름차순과 내림차순을 지정한다.
- 여러 정렬 기준을 사용할 경우 콤마(,)를 사용하여 구분한다.
쿼리 메서드에서 정렬 부분을 분리
@SpringBootTest
class ProductRepositoryTest {
@Autowired
ProductRepository productRepository;
@Test
void sortingAndPagingTest() {
//.. 상단 코드 생략..//
System.out.println(productRepository.findByName("pen", getSort()));
}
private Sort getSort() {
return Sort.by(
Order.asc("price"),
Order.desc("stock")
);
}
}
페이징 처리
- 데이터베이스의 로코드를 개수로 나눠 페이지를 구분하는 것을 의미한다.
- ex) 25개의 레코드가 있다면 레코드를 7개씩, 총 4개의 페이지로 구분하고 그 중에서 특정 페이지를 가져오는 것이다.
- 흔히 볼 수 있는 웹 페이지에서 각 페이지를 구분해서 데이터를 제공할 때, 그에 맞는 데이터를 요청하는 것이다.
- JPA에서는 이 같은 페이징 처리를 위해 Page와 Pagable을 사용한다.
페이징 처리를 위한 쿼리 메서드 예시
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByName(String name, Pageable pageable);
}
- 리턴 타입으로 Page를 설정하고, 매개변수에는 Pagable 타입의 객체를 정의한다.
페이징 쿼리 메서드를 호출하는 방법
Page<Product> productPage = productRepository,findByName("pen", PageRequest.of(0, 2));
- 리턴 타입을 Page 객체로 받아야하기 때문에 Page<Product>로 타입을 선언하여 객체를 리턴받는다.
- Pagable 파라미터를 전달하기 위해 PageRequest 클래스를 사용한다.
PageRequest 사용을 위한 매개변수 조합
of 메서드 | 매개변수 설명 | 비고 |
of(int page, int size) | 페이지 번호(0부터 시작), 페이지당 데이터 개수 | 데이터를 정렬하지 않는다. |
of(int page, int size, Sort) | 페이지 번호, 페이지당 데이터 개수, 정렬 | sort에 의한 정렬 |
of(int page, int size, Direction, String ··· properties) |
페이지 번호, 페이지당 데이터 개수, 정렬 방향, 속성(컬럼) | Sort.by(direction, properties) 에 의해 정렬 |
Page 쿼리(Hibernate)
- 쿼리 로그에는 select 쿼리에 limit 쿼리가 포함되어 있다.
- 페이지 번호를 0이 아닌 1 이상의 숫자로 설정하면 offset 키워드도 포함되어 레코드 목록을 구분해서 가져오게 된다.
Hibernate:
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=? limit?
Hibernate:
select
count(product0_.number) as col_0_0_
from
product product0_
where
product0_.name=?
페이지 객체의 데이터 출력
Page<Product> productPage = productRepository,findByName("pen", PageRequest.of(0, 2));
System.out.println(productPage.getContent());
- Page 객체를 그대로 출력하면 해당 객체의 값을 보여주지 않는다.
- 몇 번째 페이지에 해당하는지만 확인할 수 있다.
- getContent() 메서드를 사용해 출력하면 배열 형태로 값이 출력된다.
반응형
'Book > 스프링부트 핵심가이드' 카테고리의 다른 글
@Query 어노테이션 관련 내용 정리 (2) | 2023.11.09 |
---|---|
Spring Data JPA 쿼리 메서드 개념과 사용 방법 (0) | 2023.11.08 |
lombok 설정 방법과 주요 어노테이션 (1) | 2023.11.03 |
댓글