Hibernate Query Language를 타입에 안전한 방식으로 실행하기 위한 목적으로 만들어짐
기존 Query는 String의 연결 (Ex) “select” + “~”)을 통해 작성했다. 이는 가독성이 좋지 않을 뿐더러 오류 발생 여부도 쿼리 발생 시점에 알 수 있기 때문에 타입 안전성이 보장되지 않았다. 따라서 이를 도메인 모델로 변경해 직접 쿼리에 반영되도록 하고 자동완성 기능을 사용함으로써 안전성을 더욱 높이고 오류 여부를 컴파일 단계에서 알 수 있도록 한다.
build.gradle
// queryDSL
buildscript {
ext {
queryDslVersion = "5.0.0"
}
}
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.8'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
// querydsl 플러그인 추가
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}
group = 'com.study'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
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'
// querydsl 디펜던시 추가
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
}
tasks.named('test') {
useJUnitPlatform()
}
// querydsl 사용할 경로 지정합니다. 현재 지정한 부분은 .gitignore에 포함되므로 git에 올라가지 않습니다.
def querydslDir = "$buildDir/generated/'querydsl'"
// JPA 사용여부 및 사용 경로 설정
querydsl {
jpa = true
querydslSourcesDir = querydslDir
}
// build시 사용할 sourceSet 추가 설정
sourceSets {
main.java.srcDir querydslDir
}
// querydsl 컴파일 시 사용할 옵션 설정
compileQuerydsl {
options.annotationProcessorPath = configurations.querydsl
}
// querydsl이 compileClassPath를 상속하도록 설정
configurations {
compileOnly {
extendsFrom annotationProcessor
}
querydsl.extendsFrom compileClasspath
}
Gradle → Tasks → other → compileQuerydsl 실행 시 build 폴더 내 Q클래스 생성
JpaQueryFactory 상속 구조
RepoCustom 인터페이스에 직접 구현해야하는 동적쿼리 등을 정의해두고 Impl이라는 구현체에 로직을 작성한다. 이후 기존 repo에서 custom과 jpaRepo를 상속하면 jpa의 메서드와 직접 구현한 동적쿼리 메서드를 다 사용할 수 있게 된다.
JPQL
@Query("select ml from MissionLog ml join fetch ml.mission m where ml.id = :id")
Optional<MissionLog> findMissionLogById(@Param("id") int id);
QueryDSL
// 기존에 Optional 타입으로 리턴받고 .orElseThrow로 예외처리를 했기 때문에
// QueryDSL의 리턴 타입도 Optional로 설정하고
// Optional.ofNullable을 통해 null 값에 상관없이 값을 가져오도록 설정
@Override
public Optional<MissionLog> findMissionLogById(int id) {
return Optional.ofNullable(queryFactory.selectFrom(missionLog)
.join(missionLog.mission, mission).fetchJoin()
.where(missionLog.id.eq(id))
.fetchOne());
}
POST / child signup
GET / child profile
queryDSL 5.0.0 버전 사용
SpringBoot 2.4.0 버전과 호환되지 않는 문제 발생
SpringBoot 버전을 2.6.0으로 업그레이드 후 재빌드하여 해결