최신자바 백엔드 기술 Spring JPA
쿼리를 자바 코드로 작성하고 문법 오류를 컴파일 시점에 잡아준다
querydsl은 별도로 추가를 해줘야한다. 버전관리는 해주는데 starter에는 없음
📌 프로젝트가 정상적으로 빌드되었는지 확인해보기 위해서는 프로젝트 빌드가 끝난 뒤 자동으로 만들어준 test 애플리케이션을 실행해 본다
🚩 주의! - 스프링 부트 3.0
스프링 부트 3.0을 선택하게 되면 다음 부분을 꼭 확인해주세요.
querydsl 스프링 부트 3.0 설정 방법
패키지 이름 변경 예)
Enable annotation processing 체크
최근 IntelliJ 버전은 Gradle로 실행을 하는 것이 기본 설정이다. 이렇게 하면 실행속도가 느리다. 다음과 같이 변경하면 자바로 바로 실행하므로 좀 더 빨라진다.
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')
}
}
본 예제는 스프링 부트 버전 2.2.2 입니다
//querydsl 추가
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
//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 추가 끝
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')
}
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
buildscript {
ext {
queryDslVersion = "5.0.0"
}
}
//querydsl 추가
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" // querydsl 라이브러리
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}" // Querydsl 관련 코드 생성 기능 제공
//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
⭐️ generated되어 생성된 Q 파일은 절대 깃에 올리면 안된다
gitignore 해줘야 한다
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
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