[JPA] QueryDSL이란? 그리고 설정 방법

QueryDSL이란 ?

SQL, JPQL 등을 코드로 작성할 수 있도록 해주는 프레임워크로 쿼리를 type-safe(컴파일시 에러 체크 가능)하게 Java 코드로 작성할 수 있습니다.

QueryDSL은 동적 쿼리를 아주 편리하게 작성할 수 있어 복잡한 동적 쿼리를 사용해야 할 때 QueryDSL을 사용하고

단순한 경우에는 Spring Data JPA를 사용합니다. 

QueryDSL은 JPA가 제공하는 JPQL을 코드로 작성할 수 있도록 도와주는 빌더 역할을 하기 때문에 JPQL의 문법에 대한 이해가 필요합니다.

 

 SQL과 JPQL의 문제점 

QueryDSL을 이해하기 전에 먼저 SQL과 JPQL의 문제점을 알아봅시다.

# SQL
String sql = "select id, item_name, price, quantity from item";

# JPQL
String jpql = "select i from Item i";

SQL, JPQL은 문자열으로 Type-check가 불가능합니다.

그래서 만약  쿼리에 오류가 있을 시 컴파일 시점에 오류를 잡을 수 없어 애플리케이션을 실행한 후에야 오류를 발견할 수 있습니다.

 

QClass

QueryDSL은 컴파일 단계에서 Entitiy를 기반으로 QClass를 생성하는데

JPAAnnotationProcessor 가 컴파일 시점에 작동해서 @Entity 등등의 어노테이션을 찾아 해당 파일들을 분석해서 QClass를 만들어 줍니다.

 

그리고 이 Entity 클래스와 매핑되는QClass를 기반으로 쿼리를 실행합니다.

Item 엔티티 클래스와 매핑된 QClass

 

QueryDSL 장점

문자가 아닌 코드로 작성하여 컴파일 시점에 오류를 잡을 수 있습니다. ( IDE의 도움 )

또한 select, from, where 등 쿼리 작성에 필요한 키워드들을 메서드 형식으로 제공하여 단순하고 쉽게 작성할 수 있습니다.

QueryDSL은 주로 JPA와 함께 많이 사용하며 가장 장점이라 할 수 있는 부분은 동적 쿼리를 아주 편리하게 작성할 수 있습니다.

 

아래는 동적 쿼리를 작성한 예시

검색 조건에 itemName이 있을 시 like로 입력한 조건에 맞는 객체 찾고

검색 조건에 maxPrice가 있을 시 검색한 maxPrice 보다 loe ( <= ) 작거나 같은 객체를 찾는 동적 쿼리 문입니다.

    public List<Item> findAll(ItemSearchCond cond) {
        String itemName = cond.getItemName();
        Integer maxPrice = cond.getMaxPrice();

        return query
                .select(QItem.item)
                .from(QItem.item)
                .where(likeItemName(itemName), maxPrice(maxPrice))
                .fetch(); // fetch() : 리스트로 결과를 반환
    }

    private BooleanExpression likeItemName(String itemName) {
        if (StringUtils.hasText(itemName)) {
            return QItem.item.itemName.like("%" + itemName + "%");
        }
        return null;
    }

    private BooleanExpression maxPrice(Integer maxPrice) {
        if (maxPrice != null) {
            return QItem.item.price.loe(maxPrice);
        }
        return null;
    }

 

 


QueryDSL 설정

이 설정 방법은 빌드 옵션이 InteliJ IDEA일 때 설정 방법입니다.

1. build.gradle에 아래 의존성 추가
dependencies {
//Querydsl 추가
	implementation 'com.querydsl:querydsl-jpa'
	annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
	annotationProcessor "jakarta.annotation:jakarta.annotation-api"
	annotationProcessor "jakarta.persistence:jakarta.persistence-api
}

 

2. gradle의 작업 옵션에서 아래의 두 작업을 clean -> complie.java로 차례대로 실행

 

3. QClass생성 확인한 후 애플리케이션 한번 실행

프로젝트의 아래의 경로에서 Entity 클래스의 이름앞에 Q가 붙은 QClass가 생성됐는지 확인합니다. ( 이 프로젝트에서 @Entity 클래스의 이름은 Item )

생성이 됐다면 어플리케이션을 한번 실행 합니다.

이제 QueryDSL의 설정이 완료되었습니다.

 

QClass를 삭제할 시

IntelliJ IDEA 옵션을 선택하면 src/main/generated 에 파일이 생성되고, 필요한 경우 Q파일을 직접 삭제해야 합니다.

gradle에 아래 스크립트를 추가하면 gradle clean 명령어를 실행할 때 src/main/generated 의 파일도 함께 삭제해줍니다.

//Querydsl 추가, 자동 생성된 Q클래스 gradle clean으로 제거
clean {
	delete file('src/main/generated')
}