Spring

[Spring Data JPA] Querydsl 세팅하기 (Springboot+mysql)

jhkimmm 2022. 1. 30. 18:22

Spring Data JPA에서 기본적으로 제공해주는 쿼리 메서드 기능으로는 복잡한 로직의 쿼리를 구현하는 데에 한계가 있고, @Query 어노테이션을 이용하여 JPQL문을 직접 문자열로 입력하는 방식도 type-safety를 지원하지 않고 컴파일 타임에 구문오류를 발견할 수 없는 것과 같은 문제점이 있습니다.

 

Querydsl은 이러한 점을 해결해주는 JPQL 작성 라이브러리이며, Spring Data JPA와 조합하여 복잡한 쿼리를 자바 코드를 통해 type-safe하게 작성 가능하고 Spring Data JPA의 Repository 인터페이스와 매끄럽게 연동되는 장점이 있습니다.

다만, 초기 세팅 과정이 번거로운 편인데 이번 포스팅에서 springboot와 mysql에 querydsl을 사용하기 위한 초기 세팅 과정을 진행해보도록 하겠습니다.

 

1. Gradle 세팅

//build.gradle
...
//springboot의 querydsl버전 의존성 정보를 불러옴
project.ext {
    querydslVersion = dependencyManagement.importedProperties['querydsl.version']
}

dependencies {
	//web
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    //mysql
    runtimeOnly 'mysql:mysql-connector-java'

    //querydsl
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation "com.querydsl:querydsl-jpa"
    implementation "com.querydsl:querydsl-collections"
    annotationProcessor "com.querydsl:querydsl-apt:${project.querydslVersion}:jpa" // querydsl JPAAnnotationProcessor 사용 지정
    annotationProcessor "jakarta.annotation:jakarta.annotation-api" // java.lang.NoClassDefFoundError (javax.annotation.Generated) 발생 대응
    annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
}
// querydsl 적용
def generated='src/main/generated'

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

// querydsl QClass 파일 위치를 잡아주는 설정
tasks.withType(JavaCompile) {
    options.getGeneratedSourceOutputDirectory().set(file(generated))
}

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

...

Querydsl은 프로젝트 내에 @Entity어노테이션이 붙은 클래스를 탐색하여 Qclass를 생성합니다.

Qclass가 생성되는 경로를 main디렉토리 아래로 변경하고, gradle clean시에 Qclass들이 들어있는 generated 디렉토리를 자동으로 삭제되는 설정을 추가하였습니다.

gradle 설정이 많이 복잡한데 이를 모두 이해하실 필요는 없다고 생각합니다.

2. application.yml

//application.yml
spring:
  profiles:
    default: dev
  datasource:
    url: jdbc:mysql://localhost:3306/(Connection명)
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: ''
  jpa:
    open-in-view: false
    show-sql: true
    properties:
      hibernate:
        format_sql: true
    hibernate:
      ddl-auto: update
    database: mysql

 

설정을 마친 후 Gradle의 compileJava를 실행했을 때 main 디렉토리 하위에 Qclass들이 담겨있는 generated 디렉토리가 생성되어야 합니다.

3. Configuration 생성

@Configuration
public class QuerydslConfiguration {
    @PersistenceContext
    EntityManager em;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(em);
    }
}

4. mysql 연결

데이터 소스를 생성해서 mysql과 연결해주시고 프로젝트를 실행했을 때 정상적으로 실행된다면 성공입니다.

(URL은 직접 생성하신 DB의 URL을 입력해주셔야 합니다.)

 

5. 간단한 예시

 

@Repository
@RequiredArgsConstructor
public class NoteRepositoryCustom {
    private final JPAQueryFactory queryFactory;

    private final QNote note = QNote.note;
    private final QUser user = QUser.user;

    public Optional<Note> findNoteById(Long noteId){
        Note result = queryFactory.selectFrom(note)
                .join(note.writer, user).fetchJoin()
                .where(note.id.eq(noteId))
                .fetchOne();

        return result == null ? Optional.empty() : Optional.of(result);
    }
}