728x90
반응형
@Query
간단한 쿼리를 처리할 때 쿼리 메소드를 사용하면 유용하지만 복잡한 쿼리를 다루기에는 적합하지 않음.
그럴 때 @Query 어노테이션을 이용하면 SQL과 유사한 JPQL(Java Persistence Query Language)
객체지향 쿼리 언어를 통해 복잡한 쿼리를 처리할 수 있음.
public interface ItemRepository extends JpaRepository<Item, Long> {
@Query("select i from Item i where i.itemDetail like %:itemDetail% order by i.price desc")
List<Item> findByItemDetail(@Param("itemDetail") String itemDetail);
//@Param 어노테이션을 잉ㅇ하여 파라미터로 넘어온 값을 JPQL에 들어갈 변수로 지정해줄 수 있음.
}
만약 기존의 데이터베이스에서 사용하던 쿼리를 그대로 사용해야 할 때는
@Query 의 nativeQuery 속성을 사용하면 기존 쿼리를 그대로 활용할 수 있음.
하지만 특정 데이터베이스에 종속되는 쿼리문을 사용하기 때문에 데이터베이스에 대해 독립적이라는 장점을 잃음.
@Query(value = "select * from item i where i.tiem_detail like %:itemDeatil% order by i.price desc", nativeQuery = true)
Querydsl
@Query 도 단점이 있다.
JPQL 문법으로 문자열을 입력하기 때문에 잘못 입력하면 컴파일 시점에서 에러를 발견할 수 없음.
이를 보완한 방법이 Querydsl 임.
Querydsl은 JPQL을 코드로 작성할 수 있도록 도와주는 빌더 API 이다.
Querydsl 장점
- 고정된 SQL문이 아닌 조건에 맞게 동적으로 쿼리를 생성할 수 있다.
- 비슷한 쿼리를 재사용할 수 있으며 제약 조건 조립 및 가독성을 향상시킬 수 있다.
- 문자열이 아닌 자바 소스코드로 작성하기 때문에 컴파일 시점에 오류를 발견할 수 있다.
- IDE의 도움을 받아서 자동 완성 기능을 이용할 수 있기 때문에 생상성을 향상 시킬 수 있다.
//마찬가지로 의존성과 플러그인을 주입시켜주면 됌
@SpringBootTest
@TestPropertySource(locations="classpath:application-test.properties")
class ItemRepositoryTest {
@PersistenceContext
EntityManager em;
//영속성 컨텍스트를 사용하기 위해 @PersistenceContext 어노테이션을 이용해 엔티티 매니저 빈을 주입.
@Test
@DisplayName("Querydsl test")
public void queryDslTest() {
this.createItemList();
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
//쿼리를 동적으로 생성. 생성자의 파라미터로는 엔티티 매니저 객체를 넣어줌.
QItem qItem = QItem.item;
//Querydsl 을 통해 쿼리를 생성하기 위해 플러그인을 통해 자동으로 생성된 QItem 객체를 이용.
JPAQuery<Item> query = queryFactory.selectFrom(qItem)
.where(qItem.itemSellStatus.eq(ItemSellStatus.SELL))
.where(qItem.itemDetail.like("%" + "test deatil" + "%"))
.orderBy(qItem.price.desc());
//자바 소스코드지만 SQL문과 비슷하게 작성 할 수 있음.
List<Item> itemList = query.fetch();
//JPAQuery 메소드 중 하나인 fetch를 이용해서 쿼리 결과를 리스트로 반환.
for(Item item : itemList) {
System.out.println(item.toString());
}
}
}
JPAQuery 데이터 반환 메소드
| 메소드 | 기능 |
| List<T> fetch() | 조회 결과 리스트 반환 |
| T fetchOne | 조회 대상이 1건인 경우 제네릭으로 지정한 타입 반환 |
| T fetchFirst() | 조회 대상 중 1건만 반환 |
| Logn fetchCount() | 조회 대상 개수 반환 |
| QueryResult<T> fetchResults() | 조회한 리스트와 전체 개수를 포함한 QueryResults 반환 |
QuerydslPredicateExecutor 인터페이스 정의 메소드
//QuerydslPredicateExecutor
public interface ItemRepository extends JpaRepository<Item, Long>, QuerydslPredicateExecutor<Item> {}
Predicate 조건이 맞다 고 판단하는 근거를 함수로 제공하는 것.
Repository에 Predicate를 파라미터로 전달하기 위해 인터페이스를 상속받음.
| 메소드 | 기능 |
| long count(Predicate) | 조건에 맞는 데이터의 총 개수 반환 |
| boolean exists(Predicate) | 조건에 맞는 데이터 존재 여부 반환 |
| Iterable findAll(Predicate) | 조건에 맞는 모든 데이터 반환 |
| Page<T> findAll(Predicate, pageable) | 조건에 맞는 페이지 데이터 반환 |
| Iterable findAll(Predicate, Sort) | 조건에 맞는 정렬된 데이터 반환 |
| T findOne(Predicate) | 조건에 맞는 데이터 1개 반환 |
//ItemRepositoryTest
@SpringBootTest
@TestPropertySource(locations="classpath:application-test.properties")
class ItemRepositoryTest {
public void createItemList() {
for(int i=1, i<=5; i++) {
Item item = new Item();
item.setPrice(10000 + i);
......
itemRepository.save(item);
}
for(int i=6, i<=10; i++) {
Item item = new Item();
item.setPrice(10000 + i);
......
itemRepository.save(item);
}
}
@Test
@DisplayName("Querydsl test")
public void queryDslTest() {
this.createItemList();
BooleanBuilder booleanBuilder = new BooleanBuilder();
//BooleanBuilder는 쿼리에 들어갈 조건을 만들어 주는 빌더라고 생각하면 됌.
//Predicate를 구현하고 있으며 메소드 체인 형식으로 사용 가능.
QItem item = QItem.item;
String itemDetail = "test detail";
int price = 10003;
String itemSellStatus = "SELL";
booleanBuilder.and(item.itemDetail.like("%" + itemDetail + "%"));
booleanBuilder.and(item.price.gt(price));
//필요한 상품을 조회하는데 필요한 "and" 조건을 추가.
//아래 소스에서 상품의 판매상태가 셀일 때만 booleanBuilder에 판매상태 조건을 동적으로 추가.
if(StringUtils.equals(itemSellStatus, ItemSelleStatus.SELL)) {
booleanBuilder.and(item.itemSellStatus.eq(ItemSellStatus.SELL));
}
Pageable pageable = PageRequest.of(0, 5);
//데이터를 페이징해 조회하도록 PageRequest.of()메소드를 이용해 Pageable 객체를 생성.
//첫 번째 인자는 조회할 페이지의 번호, 두번 째는 한 페이지당 조회할 데이터의 개수를 넣어 줌.
Page<Item> itemPagingResult = itemRepository.findAll(booleanBuilder, pageable);
Sustem.out.println("total elements : " + itemPagingResult.getTotalElements());
List<Item> resultItemList = itemPagingResult.getContent();
....
}}}728x90
반응형
'Spring boot' 카테고리의 다른 글
| 스프링 시큐리티(Spring Security) (0) | 2023.09.06 |
|---|---|
| Thymeleaf(타임리프) (0) | 2023.09.04 |
| 쿼리 메소드 (0) | 2023.09.02 |
| @Entity 와 @Repository 설계 (0) | 2023.09.01 |
| JPA(Java Persistence API) (0) | 2023.08.31 |