querydsl을 왜 사용해야 할까?
● 실무에서 쿼리를 문자열로 다루는 것을 기억해보면 띄어쓰기, 문법 오류 등 실수하는 경우가 많다.
● 문제는 비즈니스가 복잡할수록 이 오류를 찾기가 쉽지 않다.
● 또한 런타임 때 실제 코드를 실행해봐야지만 문제를 발견할 수 있다.
● 컴파일 시점에 미리 에러를 알 수 있다면 얼마나 좋을까?
● 또한 반복되는 where 조건절을 함수로 분리하여 가독성도 확보하고 재사용 할 수 있다면?
● QueryDSL은 타입 안전한 SQL 빌더로, JPA의 한계를 보완하고 복잡한 쿼리를 우아하게 다루기 위한 필수 도구이다.
starter 설정

gradle 설정
● build.gradle > dependencies에 다음을 추가한다.
// querydsl setting
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"
추가된 build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.3'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'com.futuregoing'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
//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"
}
tasks.named('test') {
useJUnitPlatform()
}
application.yml 설정
spring:
datasource:
url: jdbc:mysql://주소:3306/spring_lecture?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC
username: 아이디
password: 비밀번호
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: create
properties:
hibernate:
format_sql: true
# System out 출력
# show_sql: true
highlight_sql: true
# Logger 출력
logging:
level:
org.hibernate.SQL: debug
org.hibernate.orm.jdbc.bind: trace
spring.jpa.hibernate.ddl-auto: create
● 애플리케이션 실행 시점에 테이블을 drop 하고 다시 create한다.
JPA DB 스키마 자동 생성 이상과 현실
객체 지향 애플리케이션은 테이블이 아닌 객체 구조에 집중해야 한다. ● JPA는 엔티티 클래스 정의만으로 DDL을 애플리케이션 실행 시점에 자동으로 생성해준다. ● DDL 생성 기능은 JPA의 실행 로
cactuslog.tistory.com
spring.jpa.properties.hibernate.show_sql: true
● System.out에 하이버네이트 실행 SQL을 남긴다.
● Logger를 통해 출력하려면 사용하지 않는다.
loggin.level 설정
● Logger를 통해 하이버네이트 실행 SQL을 남긴다. (debug level)
● 파라미터 바인딩 값 출력 (trace)
[Hibernate]
insert
into
member
(name)
values
(?)
org.hibernate.orm.jdbc.bind: binding parameter (1:VARCHAR) <- [JPA]
쿼리, 파라미터 로깅은 개발 환경에서 사용한다.
스프링부트 3 설정 주의사항
1. Java 17 이상 사용
2. javax 대신 jakarta 패키지 사용
3. 빌드시 IntelliJ IDEA가 아니라 Gradle을 선택

테스트 Entity 생성
package com.futuregoing.lecturequerydsl;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
@Entity
@Getter
public class HelloEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
IDENTITY 전략은 데이터베이스의 auto increment 기능을 이용하여 엔티티의 primary key 값을 자동으로 생성한다.
Entity 기반으로 Q타입 생성
1. Gradle > Tasks > build > clean
2. Gradle > Tasks > other > compileJava

build 폴더에 Q타입이 생성된 것을 확인할 수 있다.

QHelloEntity
@Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QHelloEntity extends EntityPathBase<HelloEntity> {
private static final long serialVersionUID = 1306507894L;
public static final QHelloEntity helloEntity = new QHelloEntity("helloEntity");
public final NumberPath<Long> id = createNumber("id", Long.class);
public QHelloEntity(String variable) {
super(HelloEntity.class, forVariable(variable));
}
public QHelloEntity(Path<? extends HelloEntity> path) {
super(path.getType(), path.getMetadata());
}
public QHelloEntity(PathMetadata metadata) {
super(HelloEntity.class, metadata);
}
}
Q타입 이란?
1. querydsl을 사용하여 타입 안전한 쿼리를 생성할 때 사용되는 클래스이다.
2. Q타입 클래스는 엔티티 클래스에 해당하는 메타 모델을 표현한다.
3. 이 메타 모델을 사용하여 SQL 또는 JPQL 쿼리를 타입 안전 방식으로 구성할 수 있다.
4. 컴파일 타임에 쿼리의 올바름을 검증할 수 있어, 런타임 시 발생할 수 있는 오류를 미리 방지할 수 있다.
5. 개발 환경에서 Q타입을 사용하면 필드 이름과 메서드를 자동으로 완성할 수 있어, 개발 효율성을 높일 수 있다.
6. Q타입을 사용하면 복잡한 조건을 가진 동적 쿼리를 보다 쉽게 구성할 수 있다.
테스트 코드로 Q타입 동작 확인
package com.futuregoing.lecturequerydsl;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
@Transactional
class LectureQuerydslApplicationTests {
@Autowired
EntityManager em;
@Test
void contextLoads() {
HelloEntity helloEntity = new HelloEntity();
em.persist(helloEntity);
JPAQueryFactory query = new JPAQueryFactory(em);
QHelloEntity qHelloEntity = QHelloEntity.helloEntity;
HelloEntity result = query.selectFrom(qHelloEntity)
.fetchOne();
Assertions.assertThat(result).isEqualTo(helloEntity);
Assertions.assertThat(result.getId()).isEqualTo(helloEntity.getId());
}
}