쿼리 메소드를 통해 상품 데이터를 조회하기로 했었다. 그런데 앞으로 조건이 많아질 것 같았다. 이럴 땐, 오히려 쿼리 메소드를 해석하는게 더 어려울 것이다. 이를 보완하는 방법으로 Spring Data Jpa에서 제공하는 @Query
어노테이션을 사용했다.
@Query
어노테이션을 이용하면 SQL과 유사한 JPQL 이라는 객체지향 쿼리 언어를 통해 복잡한 쿼리도 처리가 가능하다. JPQL은 테이블이 아닌 엔티티 객체를 대상으로 쿼리를 수행한다. 그렇기 때문에 특정 데이터베이스 SQL에 의존하지 않는다는 장점이 있다.
com.shop.repository.ItemRepository.java
package com.shop.repository;
import com.shop.entity.Item;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ItemRepository extends JpaRepository<Item, Long> {
List<Item> findByItemNm(String itemNm);
@Query("select i from Item i where i.itemDetail like %:itemDetail% order by i.price desc")
// 1.
List<Item> findByItemDetail(@Param("itemDetail") String itemDetail);
// 2.
}
SQL문이 익숙치 않아서 쿼리문 한 줄 작성하는데도 시간이 꽤 걸렸다...😥
나중에 구현할 상품 상세 설명을 파라미터로 받아서 해당 내용을 상품 상세 설명에 포함하고 있는 데이터를 조회하고, 정렬 순서는 가격이 높은 순서로 조회하게끔 했다.
@Query
어노테이션 안에 JPQL로 작성한 쿼리문을 넣어줌. @Param
어노테이션을 이용하여 파라미터로 넘어 온 값을 JPQL에 들어갈 변수로 지정JPQL을 계속 사용하다보니 불편한 점이 많았다. @Query 어노테이션 안에 JPQL 문법으로 문자열을 입력하다보니 컴파일 할때 에러를 확인할 수 없었고, 무엇보다 동적으로 쿼리를 생성하는게 어려웠다. 이를 해결하기 위해 Querydsl을 사용하기로 했다.
즉, QuerydslPredicateExecutor
인터페이스를 이용하여 상품을 조회하는 것으로 수정하였다.
com.shop.repository.ItemRepository.java
package com.shop.repository;
import com.shop.entity.Item;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface ItemRepository extends JpaRepository<Item, Long>, QuerydslPredicateExecutor<Item> {
@Query(value = "select i from Item i where i.itemDetail like %:itemDetail% order by i.price desc", nativeQuery = true)
List<Item> findByItemDetail(@Param("itemDetail") String itemDetail);
}
Constant : ItemSellStatus
Entity : Item
Repository : ItemRepository
Querydsl
의 장점에 대해 알게 되었다.QueryDslPredicateExecutor
인터페이스 정의 메소드long count(Predicate)
: 조건에 맞는 데이터의 총 개수 반환boolean exists(Predicate)
: 조건에 맞는 데이터 존재 여부 반환Iterable findAll(Predicate)
: 조건에 맞는 모든 데이터 반환Page<T> findAll(Predicate,Pageable)
: 조건에 맞는 페이지 데이터 반환Iterable findAll(Predicate, Sort)
: 조건에 맞는 정렬된 데이터 반환T findOne(Predicate)
: 조건에 맞는 데이터 1개 반환 QuerydslPredicateExecutor
인터페이스를 상속하면 Querydsl을 사용하기위해 EntityManager를 주입하여 JPAQueryFactory를 생성하고 기본 쿼리도 직접 작성해야하는 수고를 덜어줄 수 있다. 그러나 left join
이 안된다는 점에서 실무에서는 잘 사용하지 않는 인터페이스라고 한다.