티켓 예매 사이트 스프링 프로젝트를 개발하고 있다.
티켓팅 아이디로 아직 구매되지 않은 티켓들 중 n개만큼만 조회해오는 로직을 구현하려 한다.
이 때 n은 사용자가 구매를 원하는 개수에 따라 동적으로 변화하는 값이다.
limit을 사용하면 쉽게 구현할 수 있어 JpaRepository에 limit을 적용하는 방법을 찾아보게 되었다.
limt을 적용하는 방법에 관해 검색해보니 아래와 같은 방법들을 찾을 수 있었다.
1. Top keyword 사용
2. Pageable 객체 사용
3. 네이티브 쿼리 작성
그런데 위의 방법들은 전부 반려했다. 이유는 다음과 같다.
Top Keyword를 사용하면 아래와 같이 JpaRepsoitory 메소드를 작성할 수 있다.
List<User> findTop10ByName(String name);
문제는 findTopXXX Keyword를 사용하는 경우 Top뒤에 들어가는 숫자를 미리 정해줘야 한다.
하지만 내가 작성하는 로직에서는 N의 값을 동적으로 바꿀 수 있어야 한다.
그래서 반려했다.
Pageable 객체를 사용하려는 경우 아래와 같이 JpaRepository 메소드를 작성하면 된다.
List<User> findByName(String name, Pageable pageable);
메소드 호출시에는 아래와 같이 PageRequest 객체를 넘겨주면 된다.
int page = 0;
int size = 10;
var users = userRepository.findByName("name",PageRequest.of(page, size));
이때 page를 0으로 두고 size의 값(n)을 동적으로 넘겨주면 내가 원하던 limit과 같은 효과를 낼 수 있다.
하지만 이 또한 반려했다.
이유는 다음과 같다.
페이징 처리를 할때는 count 쿼리가 자동으로 호출된다. count 쿼리가 있어야 전체 페이지를 구할 수 있기 때문이다.
그런데 사실상 페이징을 사용하지 않기 때문에 count 쿼리를 날리는 것은 불필요한 쿼리를 추가로 날리는 것뿐이다.
이로 인해 성능에 영향이 가는 게 싫어서 이 방법은 반려했다.
아래와 같이 nativeQuery를 작성하여 limit을 줄 수 있다.
@Query("SELECT u FROM Users u WHERE name = ?1 LIMIT ?2", nativeQuery = true))
List<User> findByNameAndLimit(String name, Integer limit);
정 방법이 없으면 위와 같이 직접 쿼리를 작성해도 된다.
하지만 순수 Query를 작성하는 방법은..
가급적 피하고 싶었기에 후순위로 두고 다른 방법을 찾아봤다.
Spring Data JPA 공식 문서에서 방법을 찾았다.
List<User> findByLastname(Limit limit);
위와 같이 Limit 객체를 사용하는 방법이 있었다.
메소드 호출 시에는 다음과 같이 Limit객체를 넘겨주면 된다.
import org.springframework.data.domain.Limit;
var cnt = 10;
userRepository.findByLastname(Limit.of(cnt));
다행히 방법을 찾아서 좋았는데 문서 신뢰도는 조금 떨어졌다.
그 이유는 다음과 같다.
ByLastname이라는 키워드를 쓰고 있으니 파라미터로 lastname을 받아야 할 텐데... 안 받고 있다.이 방법을 이용해 실제로 티켓을 조회하는 로직은 다음과 같이 완성되었다.
List<Ticket> findByTicketingIdAndPurchaseIsNullOrderById(UUID ticketingId, Limit limit);
var tickets = ticketRepository.findByTicketingIdAndPurchaseIsNullOrderById(
ticketingId, Limit.of(ticketCount));
Spring Data JpaRepository에서 limit을 동적으로 구현하는 방법에 대해 알아봤다.
검색을 통해 알아낸 대부분의 방법(Top 키워드, Pagaeable, 순수 쿼리)은 현재 내 상황에 적합하지 않거나 번거로웠다.
추가+) JPQL에서 .setFirstResult().setMaxResult()로 구현하는 방법도 있다.
하지만 공식 문서를 통해 Limit 객체를 사용하는 방법을 찾아 적용해본 결과, 손쉽게 원하는 기능을 작성할 수 있었다.
나처럼 동적 사이즈로 limit을 JpaRepository에 적용하려는 사람들이 고생하지 않기를 바라며 이 글을 포스팅한다.