본문 바로가기

Spring boot

Spring DATA JPA

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