1 분 소요

QueryDSL을 맛 만 보자

  • http://www.querydsl.com

실무에서는 조건에 따라서 실행되는 쿼리가 달라지는 동적 쿼리를 많이 사용한다. 주문 내역 검색으로 돌아 가보고, 이 예제를 QueryDSL로 바꿔보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
plugins {  
    id 'java'  
    id 'org.springframework.boot' version '3.2.1'  
    id 'io.spring.dependency-management' version '1.1.4'  
}  
  
group = 'jpabook'  
version = '0.0.1-SNAPSHOT'  
  
java {  
    sourceCompatibility = '21'  
}  
  
configurations {  
    compileOnly {  
       extendsFrom annotationProcessor  
    }  
}  
  
repositories {  
    mavenCentral()  
}  
  
dependencies {  
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'  
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'  
    implementation 'org.springframework.boot:spring-boot-starter-web'  
    implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'  
    implementation 'org.springframework.boot:spring-boot-devtools'  
    implementation 'org.springframework.boot:spring-boot-starter-validation'  
    implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5-jakarta'  
    compileOnly 'org.projectlombok:lombok'  
    runtimeOnly 'com.h2database:h2'  
    annotationProcessor 'org.projectlombok:lombok'  
    testImplementation 'org.springframework.boot:spring-boot-starter-test'  
  
    // Querydsl 추가  
    implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'  
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"  
    annotationProcessor "jakarta.annotation:jakarta.annotation-api"  
    annotationProcessor "jakarta.persistence:jakarta.persistence-api"  
  
  
}  

// Querydsl 추가  
def querydslSrcDir = 'src/main/generated'  
clean {  
    delete file(querydslSrcDir)  
}  
tasks.withType(JavaCompile) {  
    options.generatedSourceOutputDirectory = file(querydslSrcDir)  
}  
  
tasks.named('test') {  
    useJUnitPlatform()  
}

이렇게 하고 다음 other 탭에 compileJava 를 하게 되면

다음과 같이 Q파일들이 생기는 걸 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// querydsl 사용해서 findAll 을 만들어 보자  
public List<Order> findAll(OrderSearch orderSearch) {  
    JPAQueryFactory query = new JPAQueryFactory(em);  
    QOrder order = QOrder.order;  
    QMember member = QMember.member;  
  
    return query  
            .select(order)  
            .from(order)  
            .join(order.member, member)  
            .where(statusEq(orderSearch.getOrderStatus()), nameLike(orderSearch.getMemberName()))  
            .limit(1000)  
            .fetch();  
}  
  
private BooleanExpression nameLike(String memberName) {  
    if (!StringUtils.hasText(memberName)) {  
        return null;  
    }  
    return QMember.member.name.like(memberName);  
}  
  
private BooleanExpression statusEq(OrderStatus statusCond) {  
    if (statusCond== null) {  
        return null;  
    }  
    return QOrder.order.status.eq(statusCond);  
}

다음과 같이 repository 를 만들었다.. 미쳣다

결과도 잘 나온다.

QueryDSL은 SQL(JPQL)과 모양이 유사 하면서, 자바 코드로 동적 쿼리를 편리하게 생성할 수 있다.

실무에서는 복잡한 동적 쿼리를 많이 사용하게 되는데, 이때 QueryDSL을 사용하면 높은 개발 생산성을 얻으면서 동시에 쿼리 오류를 컴파일 시점에 빠르게 잡을 수 있다. 꼭 동적 쿼리가 아니라 정적 쿼리인 경우에도 다음과 같은 이유로 QueryDSL 을 사용하는 것이 좋다.

  • 직관적인 문법
  • 컴파일 시점에 빠른 문법 오류 발견
  • 코드 자동완성
  • 코드 재사용성
  • JPQL new 명령어와는 비교가 안될 정도로 깔끔한 DTO 조회를 지원한다.

QueryDSL은 JPQL을 코드로 만드는 빌더 역할을 할 뿐이다. 따라서 JPQL을 잘 이해하면 금방 배울 수 있다.

태그: ,

카테고리:

업데이트:

댓글남기기