[JPA] QueryDSL 사용하기 - 환경설정 (1)

2022. 6. 20. 15:14Web/Spring

프로젝트를 진행하면서 Lazy Loading으로 인한 N+1 문제 발생으로 인해 한꺼번에 데이터를 가져올 상황에서는 모두 jpaRepository에서 기본적으로 제공하는 @Query를 사용하여 JPQL 문법으로 작성하였다. 

 

 

 JPA에 대해 공부를 하던 도중 QueryDSL에 대해 알게 되었다. JPQL을 활용하게 되면서 MyBatis로 작성했을 때보다 훨씬 간편하다고 생각했었는데 더 편의성을 높이는 기능을 지원한다는 사실을 알게 되었다. 

http://querydsl.com/static/querydsl/4.0.1/reference/ko-KR/html_single/

 

Querydsl - 레퍼런스 문서

Querydsl은 JPA, JDO, Mongodb 모듈에서 코드 생성을 위해 자바6의 APT 어노테이션 처리 기능을 사용한다. 이 절에서는 코드 생성을 위한 다양한 설정 옵션과 APT에 대한 대안을 설명한다. 기본적으로 Query

querydsl.com

 

QueryDSL을 사용하면 쿼리를 문자 대신 Java 코드로 작성할 수 있다. 예전의 기억을 거슬러 올라갔을 때, 쿼리를 문자열로 작성하다보면 사소한 문법 실수나 기타 사항으로 오류가 발생하는 경우가 몇 번 있었다. 코드로 작성하여 이러한 문법적인 실수를 줄일 수 있다는 생각이 들긴했다.

 

공식 문서에서는 QueryDSL을 사용하게 되면서 얻는 이점을 아래와 같이 설명하고 있다. 

 

 타입에 안전하도록 도메인 모델을 변경하면 소프트웨어 개발에서 큰 이득을 얻게 된다. 도메인의 변경이 직접적으로 쿼리에 반영되고, 쿼리 작성 과정에서 코드 자동완성 기능을 사용함으로써 쿼리를 더 빠르고 안전하게 만들 수 있게 된다.

... (중략)... 


Querydsl의 핵심 원칙은 타입 안정성(Type safety)이다. 도메인 타입의 프로퍼티를 반영해서 생성한 쿼리 타입을 이용해서 쿼리를 작성하게 된다. 또한, 완전히 타입에 안전한 방법으로 함수/메서드 호출이 이루어진다.
또 다른 중요한 원칙은 일관성(consistency)이다. 기반 기술에 상관없이 쿼리 경로와 오퍼레이션은 모두 동일하며, Query 인터페이스는 공통의 상위 인터페이스를 갖는다.

모든 쿼리 인스턴스는 여러 차례 재사용 가능하다. 쿼리 실행 이후 페이징 데이터와 프로젝션 정의는 제거된다.

 

전체를 다 읽어보지 않았지만 쭉 내려서 살펴보니 join, groupby, subquery, orderby 기능을 제공하고 있다. 

 

QueryDSL 모듈은 JPA와 Hibernate API 두 개를 동시에 지원하고 있다고 한다. 

JPA API를 사용하려면 JPAQuery를, Hibernate API를 사용하려면 HibernateQuery를 사용하면 된다고 한다. 

 

EntityManager entityManager = new EntityManager();

// where entityManager is a JPA EntityManager
JPAQuery query = new JPAQuery(entityManager);

// where session is a Hibernate session
HibernateQuery query = new HibernateQuery(session);

 

 

한 번 사용해보기 위해 gradle 설정부터 해보도록 하겠다. 

 

참고한 사이트는 아래와 같았다. 

https://stackoverflow.com/questions/62521275/problem-with-generating-querydsl-classes-with-gradle

 

다른 것들은 이미 설정 되어 있어서 querydsl 부분만 implemetation과 annotationprocessor를 추가하였다. 

def querydslVersion = '4.3.1'

dependencies {

    // Querydsl
    implementation group: 'com.querydsl', name: 'querydsl-jpa', version: querydslVersion
    implementation group: 'com.querydsl', name: 'querydsl-apt', version: querydslVersion
    implementation group: 'com.querydsl', name: 'querydsl-core', version: querydslVersion


    annotationProcessor group: 'com.querydsl', name: 'querydsl-apt', version: querydslVersion
    annotationProcessor group: 'com.querydsl', 'name': 'querydsl-apt', version: querydslVersion, classifier: 'jpa'

}

딱 이 부분만 추가하였다.

 

 

추가적으로 검색을 하다보니 QueryDSL gradle로 환경 설정하는데 있어서 문제가 좀 있는 거 같았다. (http://honeymon.io/tech/2020/07/09/gradle-annotation-processor-with-querydsl.html)

결론적으로 말하자면 인텔리제이 2020년 이상 버전을 사용하는 사용자들은 plugin을 사용하면 오류가 나니 annotationProcessor를 사용하라는 말이었다. 

 

build를 시켰는데 아래와 같은 오류가 나서 다시 검색을 하였다.

 

이번에는 인프런에 있는 한 페이지를 활용해서 다시 설정을 해봤다. 

https://www.inflearn.com/questions/355723

 

compileQuerydsl 오류 - 인프런 | 질문 & 답변

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼

www.inflearn.com

 

결과는 잘 되었다.

 

QueryDSL 설정은 아래와 같다. 

buildscript {
	ext {
		queryDslVersion = '5.0.0'
	}
}

plugins {
	id 'org.springframework.boot' version '2.6.5'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
	id 'java'
}

group = 'com.house'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	// 기타 설정 생략
	//Querydsl
	implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
	implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
}

tasks.named('test') {
	useJUnitPlatform()
}

//querydsl 추가 시작
def querydslDir = "$buildDir/generated/querydsl"

querydsl {
	jpa = true
	querydslSourcesDir = querydslDir
}
sourceSets {
	main.java.srcDir querydslDir
}
compileQuerydsl{
	options.annotationProcessorPath = configurations.querydsl
}
configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
	querydsl.extendsFrom compileClasspath
}

 

검색을 하던 도중에 안 사실인데 QueryDSL이 스프링 비표준 오픈소스라 단순히 implementation 외에 신경 써야 할 부분이 많았던 거 같다. 버전도 자동으로 업그레이드가 되지 않기에 구 버전 인텔리제이를 쓰는 사람들은 상관이 없지만 2020년 이후 버전을 쓰는 사람들은 버전을 따로 설정을 해야한다고 하였다. 추가로 gradle 빌드를 완료하였을 때 build 하위 파일에 QueryDSL 디렉토리가 생성되었는데 이것도 따로 설정해줘야 해야 했다.  (querydslDir 경로가 생성 경로)

 

보니까 지금까지 생성한 Entity에 Q가 붙어서 생성된 것을 확인할 수 있었다.