JPQL을 QueryDSL로 변경해보자

정종일·2023년 2월 27일
0

Spring

목록 보기
3/18

QueryDSL은?

Hibernate Query Language를 타입에 안전한 방식으로 실행하기 위한 목적으로 만들어짐

기존 Query는 String의 연결 (Ex) “select” + “~”)을 통해 작성했다. 이는 가독성이 좋지 않을 뿐더러 오류 발생 여부도 쿼리 발생 시점에 알 수 있기 때문에 타입 안전성이 보장되지 않았다. 따라서 이를 도메인 모델로 변경해 직접 쿼리에 반영되도록 하고 자동완성 기능을 사용함으로써 안전성을 더욱 높이고 오류 여부를 컴파일 단계에서 알 수 있도록 한다.


1. QueryDSL 사전 설정

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
}

Build

Gradle → Tasks → other → compileQuerydsl 실행 시 build 폴더 내 Q클래스 생성

JpaQueryFactory 상속 구조

RepoCustom 인터페이스에 직접 구현해야하는 동적쿼리 등을 정의해두고 Impl이라는 구현체에 로직을 작성한다. 이후 기존 repo에서 custom과 jpaRepo를 상속하면 jpa의 메서드와 직접 구현한 동적쿼리 메서드를 다 사용할 수 있게 된다.

JPQL → QueryDSL 리팩토링

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());
}

TEST

POST / child signup

GET / child profile


수정 사항

queryDSL 5.0.0 버전 사용

SpringBoot 2.4.0 버전과 호환되지 않는 문제 발생

SpringBoot 버전을 2.6.0으로 업그레이드 후 재빌드하여 해결

profile
제어할 수 없는 것에 의지하지 말자

0개의 댓글