[querydsl] QueryDSL 환경 설정

may_yun·2023년 4월 20일
0

JPA

목록 보기
1/15

Querydsl

최신자바 백엔드 기술 Spring JPA
쿼리를 자바 코드로 작성하고 문법 오류를 컴파일 시점에 잡아준다

  • 쿼리는 자바 코드로 작성하기 때문에 컴파일 시점에 에러를 잡아줌

    예를 들어 m과 where절 사이의 공백이 없기 때문에 에러가 발생하나 알 수 없다
    • 자바 코드 자동완성을 지원받을 수 있다
    • 메서드를 사용할 수 있다
  • 동적 쿼리 문제 해결
  • 쉽게 작성 가능
  • Spring Data JPA + Querydsl 조합은 코드 반복 작업을 줄여주고
    실무에서는 필수로 사용해야한다

프로젝트 환경 설정

start.spring.io

querydsl은 별도로 추가를 해줘야한다. 버전관리는 해주는데 starter에는 없음

📌 프로젝트가 정상적으로 빌드되었는지 확인해보기 위해서는 프로젝트 빌드가 끝난 뒤 자동으로 만들어준 test 애플리케이션을 실행해 본다

🚩 주의! - 스프링 부트 3.0
스프링 부트 3.0을 선택하게 되면 다음 부분을 꼭 확인해주세요.
querydsl 스프링 부트 3.0 설정 방법

  1. Java 17 이상을 사용해야 합니다.
  2. javax 패키지 이름을 jakarta로 변경해야 합니다.
    오라클과 자바 라이센스 문제로 모든 javax 패키지를 jakarta로 변경하기로 했습니다. 3. H2 데이터베이스를 2.1.214 버전 이상 사용해주세요.

패키지 이름 변경 예)

  • JPA 애노테이션
    • javax.persistence.Entity jakarta.persistence.Entity
  • 스프링에서 자주 사용하는 @PostConstruct 애노테이션
    • javax.annotation.PostConstruct -> jakarta.annotation.PostConstruct
  • 스프링에서 자주 사용하는 검증 애노테이션
    • javax.validation jakarta.validation

Lombok setting

    1. Lombok 플러그인 설치
    1. Preferences -> Lombok 검색 -> Annotation Processors -> Enable annotation processing 체크
      이걸 체크해줘야 롬복이 정상 작동한다

IntelliJ Gradle 대신에 자바로 바로 실행하기

최근 IntelliJ 버전은 Gradle로 실행을 하는 것이 기본 설정이다. 이렇게 하면 실행속도가 느리다. 다음과 같이 변경하면 자바로 바로 실행하므로 좀 더 빨라진다.

  • Preferences -> Build,Execution,Deployment -> BuildTools -> Gradle
  1. Build and run using: Gradle IntelliJ IDEA
  2. Run tests using: Gradle IntelliJ IDEA

Querydsl 설정

직접 설정하는 방법

gradle 의 경우 querydsl-plugin 버전 업데이트가 잘 안되는 경우가 있다.
실제 springboot 1 -> 2로 이동할 때 버그가 생기는 문제가 있었기 때문에
직접 의존성 추가를 할 수 있다.

// queryDSL 설정
    implementation "com.querydsl:querydsl-jpa"
    implementation "com.querydsl:querydsl-core"
    implementation "com.querydsl:querydsl-collections"
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa" // querydsl JPAAnnotationProcessor 사용 지정
    annotationProcessor "jakarta.annotation:jakarta.annotation-api" // java.lang.NoClassDefFoundError (javax.annotation.Generated) 대응 코드
    annotationProcessor "jakarta.persistence:jakarta.persistence-api" // java.lang.NoClassDefFoundError (javax.annotation.Entity) 대응 코드
  • global 영역에 print(dependencyManagement) 넣어주면 버전 확인이 가능하다

  • 아래 코드가 없어도 QueryDSL은 잘 작동한다. 단 IDE와 queryDSL의 충돌을 방지 및 해결하기 위해 아래와 같은 설정을 해준다. IDE와 queryDSL의 중복을 막기위해 위치를 꺼내 놓는 추가 설정을 한 것

// Querydsl 설정부
def generated = 'src/main/generated'

// querydsl QClass 파일 생성 위치를 지정
tasks.withType(JavaCompile) {
    options.getGeneratedSourceOutputDirectory().set(file(generated))
}

// java source set 에 querydsl QClass 위치 추가
sourceSets {
    main.java.srcDirs += [ generated ]
}

// gradle clean 시에 QClass 디렉토리 삭제
clean {
    delete file(generated)
}

// Heroku 설정
jar {
    manifest {
        attributes('Main-Class': 'com.fastcampus.projectboard.FastCampusProjectBoardApplication')
    }
}

1. Build.gradle

본 예제는 스프링 부트 버전 2.2.2 입니다

  • plugins에 querydsl 플러그인 추가
//querydsl 추가
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
  • dependiencies에 querydel 라이브러리 추가
//querydsl 추가
implementation 'com.querydsl:querydsl-jpa'

  • querydsl 추가
    : 빌드와 관련된 프로세싱

  • def querydslDir = "$buildDir/generated/querydsl"

//querydsl 추가 시작
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
    jpa = true
    querydslSourcesDir = querydslDir
}
sourceSets {
    main.java.srcDir querydslDir
}

configurations {
    querydsl.extendsFrom compileClasspath
}
compileQuerydsl {
    options.annotationProcessorPath = configurations.querydsl
}
//querydsl 추가 끝
  • Querydsl 스프링부트 3.X 설정
plugins {
	id 'java'
	id 'org.springframework.boot' version '3.0.2'
	id 'io.spring.dependency-management' version '1.1.0'
}

group = 'study'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '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'
	implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'
	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"
}

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

clean {
	delete file('src/main/generated')
}

Querydsl 스프링부트 2.X 설정

  • 2.6.5
ext["hibernate.version"] = "5.6.5.Final"
  • 디펜던시 라이브러리 추가
//Querydsl 추가
	implementation 'com.querydsl:querydsl-jpa'
	annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
	annotationProcessor "jakarta.annotation:jakarta.annotation-api"
	annotationProcessor "jakarta.persistence:jakarta.persistence-api"
//Querydsl 추가, 자동 생성된 Q클래스 gradle clean으로 제거
clean {
	delete file('src/main/generated')
}
  • 전체
plugins {
    id 'java'
    id 'org.springframework.boot' version '2.7.5'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'study'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

ext["hibernate.version"] = "5.6.5.Final"

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    //querydsl 추가
    implementation 'com.querydsl:querydsl-jpa'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
    annotationProcessor "jakarta.annotation:jakarta.annotation-api"
    annotationProcessor "jakarta.persistence:jakarta.persistence-api"
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    //테스트에서 lombok 사용
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
}

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

//Querydsl 추가, 자동 생성된 Q클래스 gradle clean으로 제거
clean {
    delete file('src/main/generated')
}
  • Querydsl 스프링부트 2.7.5

      1. buildscript 추가
buildscript {
    ext {
        queryDslVersion = "5.0.0"
    }
}
    1. 디펜던시 라이브러리 추가
//querydsl 추가
    implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" // querydsl 라이브러리
    annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}" //  Querydsl 관련 코드 생성 기능 제공
    1. 빌드
//querydsl 추가 시작 (위에 plugin 추가 부분과 맞물림)
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
    jpa = true
    querydslSourcesDir = querydslDir
}

sourceSets { // IDE의 소스 폴더에 자동으로 넣어준다.
    main.java.srcDir querydslDir
}

configurations {
    querydsl.extendsFrom compileClasspath // 컴파일이 될때 같이 수행
}

compileQuerydsl {
    options.annotationProcessorPath = configurations.querydsl // Q파일을 생성해준다.
}
//querydsl 추가 끝
buildscript {
    ext {
        queryDslVersion = "5.0.0"
    }
}

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.7.5'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
    //querydsl 추가
    id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}

group = 'study'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

ext["hibernate.version"] = "5.6.5.Final"

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    //querydsl 추가
    implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" // querydsl 라이브러리
    annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}" //  Querydsl 관련 코드 생성 기능 제공
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    //테스트에서 lombok 사용
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
}

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

//querydsl 추가 시작 (위에 plugin 추가 부분과 맞물림)
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
    jpa = true
    querydslSourcesDir = querydslDir
}

sourceSets { // IDE의 소스 폴더에 자동으로 넣어준다.
    main.java.srcDir querydslDir
}

configurations {
    querydsl.extendsFrom compileClasspath // 컴파일이 될때 같이 수행
}

compileQuerydsl {
    options.annotationProcessorPath = configurations.querydsl // Q파일을 생성해준다.
}
//querydsl 추가 끝

터미널에서 해당 위치로가서 컴파일 해줄 수 있음
인텔리제이 gradle에서 Tasks -> other -> compileQuerydsl 해서 Q 파일 만드는 것과 동일

  • 제거
➜  querydsl-practice git:(master) ✗ ./gradlew clean
  • 빌드
➜  querydsl-practice git:(master) ✗ ./gradlew compileQuerydsl

2. querydsl 빌드 확인

⭐️ generated되어 생성된 Q 파일은 절대 깃에 올리면 안된다
gitignore 해줘야 한다

3. Querydsl 확인

package study.querydslpractice;

import com.querydsl.jpa.impl.JPAQueryFactory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import study.querydslpractice.entity.Hello;
import study.querydslpractice.entity.QHello;

import javax.persistence.EntityManager;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest
@Transactional
class QuerydslPracticeApplicationTests {

    @Autowired
    EntityManager em;

    @Test
    void contextLoads() {
        Hello hello = new Hello();
        em.persist(hello);

        JPAQueryFactory query = new JPAQueryFactory(em);//최신 버전에서는 JPAQueryFactory 사용을 권장
        //QHello qHello = new QHello("h");
        QHello qHello = QHello.hello; //Q 클래스에 static으로 정의해 놓은 것이 있음

        Hello result = query
                .selectFrom(qHello)//쿼리에 관련된 것은 다 Q타입을 넣어야한다
                .fetchOne();

        assertThat(result).isEqualTo(hello);
        assertThat(result.getId()).isEqualTo(hello.getId());
    }

}

querydsl-apt는 generated 했던 (QHello) 만드는 용도로 사용하는 것이고,
querydsl-jpa는 쿼리 체이닝할 때 필요한 라이브러리이다.
querydsl은 다양한 쿼리를 같은 경험으로 제공하는데 여러가지를 지원하기 때문에 우리는 JPA를 사용해서 JPA


4. H2 DB 생성

  • querydsl로 생성했음

5. spring boot 설정 - JPA/DB

  • application.yml
spring:
  datasource:
    url: jdbc:h2:tcp://localhost/~/querydsl
    username: sa
    password:
    driver-class-name: org.h2.Driver

  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
        format_sql: true
logging:
  level:
    org:
      hibernate:
        sql: debug
profile
개발 일지

0개의 댓글