본문 바로가기
개발공부/JAVA Spring

[Spring Boot] JPQL, QueryDSL 쿼리 작성

by bzerome240 2023. 3. 10.

 

JPQL (JPA Query Language)

: JPA에서 사용할 수 있는 쿼리

SELECT p FROM 엔티티타입 p WHERE p.엔티티속성 = ?1;

 

쿼리 메서드

간단한 쿼리문을 작성하기 위해 사용되는 것 (주제 + 서술어)

 

쿼리 메서드 - 주제 키워드

findBy / readBy / getBy / queryBy / searchBy / streamBy / existsBy

: 조회 

existsBy

: 특정 데이터가 존재하는지 확인

- 리턴타입 boolean

countBy

: 쿼리 결과 레코드 개수 리턴

deleteBy / removeBy

: 삭제한 횟수 리턴 또는 리턴 안함

First<number>By / Top<number>By

: 쿼리 조회 결과값 개수 제한

 


 

쿼리 메서드 - 조건자 메서드

Is / Equals

: 값의 일치를 조건으로 사용 (생략되는 경우가 많다)

(Is)Not

: 값의 불일치를 조건으로 사용

(Is)Null / (Is)NotNull

: 값이 null인지 검사

(Is)True / (Is)False

: boolean 타입으로 지정된 컬럼값 확인

(Is)GreaterThan / (Is)LessThan / (Is)Between

: 숫자나 datetime 컬럼을 대상으로 한 비교 연산에 사용 (경곗값을 포함하려면 Equal 키워드를 추가)

(Is)StartingWith (StartsWith) / (Is)EndingWith (EndsWith) / (Is)Containg (Contains) / (Is)Like

: 값의 일부를 포함하는 값을 추출할 때 사용

 


 

정렬

매개변수를 활용한 쿼리 정렬

productRepository.findByName("펜", Sort.by(Order.asc("price"), Order.desc("stock")));

메서드로 분리하여 작성

private Sort getSort() {
    return Sort.by(
        Order.asc("price"), Order.desc("stock")
    );
}

 


 

페이징 처리

리턴타입으로 Page를 설정하고 매개변수는 Pageable 타입 객체 정의

Page<Product> productPage = productRepository.findByName("펜", PageRequest.of(0,2));

of 메서드

// 페이지 번호, 페이지당 데이터 개수, 정렬 방향, 속성(컬럼)
of(int page, int size, Direction, String properties)

페이지 객체 데이터 출력 - 리턴 배열형태

System.out.println(productPage.getContent());

 


 

@Query 와 @Param 어노테이션을 사용한 쿼리 작성

  • 튜닝된 쿼리를 사용하고자 할 때 직접 SQL을 작성한다.
  • 파라미터를 바인딩하는 방식으로 메서드를 구현하면 코드의 가독성이 높아진다.
// 엔티티 타입 리턴
@Query("SELECT p FROM Product p WHERE p.name = :name")
List<Product> findByNameParam(@Param("name") String name);

// 특정 컬럼만 추출하는 쿼리
@Query("SELECT p.name, p.price FROM Product p WHERE p.name = :name")
List<Object[]> findByNameParam(@Param("name") String name);

 

단점: 컴파일 시점에 에러를 잡지 못하고 런타임 에러가 발생할 수 있다.

 


이를 해결하기 위해

 

QueryDSL

: 정접 타입을 이용해 SQL 쿼리를 생성할 수 있도록 하는 프레임워크

Fluent API를 활용해 쿼리를 생성할 수 있다.

 

장점

  • IDE 제공하는 코드 자동 완성 기능을 사용할 수 있다.
  • 문법적으로 잘못된 쿼리를 허용하지 않는다.

 

1) JPAQuery를 활용한 QueryDSL 코드

  • from절부터 작성
void queryDslTest() {
    // JPAQuery 객체를 EntityManager를 이용해 생성
    JPAQuery<Product> query = new JPAQuery(entityManager);
    QProduct qProduct = QProduct.product;
    
    // 빌더 형식으로 쿼리 작성
    List<Product> productList = query
        .from(qProduct)
        .where(qProduct.name.eq("펜"))
        .orderBy(qProduct.price.asc())
        .fetch(); // List 타입으로 리턴 받기 위해
}

 

2) JPAQueryFactory를 활용한 QueryDSL 코드

  • select절부터 작성 가능
void queryDslTest() {
    JPAQueryFactory<Product> query = new JPAQueryFactory(entityManager);
    QProduct qProduct = QProduct.product;
    
    // select 여러개인 경우 Tuple
    List<Tuple> productList = query
        .select(qProduct.name, qProduct.price)
        .from(qProduct)
        .where(qProduct.name.eq("펜"))
        .orderBy(qProduct.price.asc())
        .fetch(); // List 타입으로 리턴 받기 위해
}

 

QueryDSL 컨피그 파일 생성

@Bean 객체로 등록해두면 매번 객체를 초기화하지 않고 스프링 컨테이너에서 가져다 쓸 수 있다.

@Configuration
public class QueryDSLConfiguration {
    @PersistenceContext
    EntityManager entityManager;
    
    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(entityManager);
    }
}
@Autowired
JPAQueryFactory jpaQueryFactory;

@Test
void queryDslTest() {
    QProduct qProduct = QProduct.product;
    
    List<Tuple> productList = jpaQueryFactory
        .select(qProduct.name, qProduct.price)
        .from(qProduct)
        .where(qProduct.name.eq("펜"))
        .orderBy(qProduct.price.asc())
        .fetch(); // List 타입으로 리턴 받기 위해
}
728x90
반응형

'개발공부 > JAVA Spring' 카테고리의 다른 글

[Spring Boot] JPA 영속성 전이 cascade, 고아객체  (0) 2023.03.27
[Spring Boot] JPA Auditing  (0) 2023.03.11
[Spring Boot] Redis config  (0) 2023.03.10
shorten url  (0) 2023.03.06
[Spring Boot] 테스트 코드 작성 관련 정리  (0) 2023.03.03

댓글