티스토리 뷰

개요

  • Java 진영에서 RDBMS에 접근하는 방법은 기존의 MyBatis가 지배하던 시대에서 JPA로 빠르게 이동하고 있다. 특히, Spring Data JPA의 등장으로 불필요한 코드가 상당히 줄어들면서 새로 시작하는 프로젝트는 모두 Spring Data JPA로 구현하는 추세이다. 하지만, 여전히 RAW SQL의 수요가 존재하기 때문에 컴파일 타임에서의 타입 세이프를 보장하는 Querydsl, jOOQ와 같은 라이브러리가 JPA를 보조하는 형태로 인기를 끌고 있다.(특히, 보고서 목적의 복잡한 SELECT 쿼리가 필요한 경우가 많다.) 이번 글에서는 Kotlin, Spring Boot, Spring Data JPA 환경에서 Querydsl을 이용하여 타입 세이프를 보장하는 쿼리를 작성하는 방법을 소개하고자 한다.

build.gradle

  • 가장 먼저, 프로젝트 루트의 /build.gradle 파일에 아래 내용을 추가한다.
buildscript {
    ext {
        kotlinVersion = '1.3.11'
        springBootVersion = '2.1.1.RELEASE'
        querydslVersion = '4.2.1'
    }
}
plugins {
    id "org.jetbrains.kotlin.plugin.jpa" version "1.3.11"
}

apply plugin: 'idea'
apply plugin: 'kotlin-kapt'

dependencies {
    compile group: 'com.querydsl', name: 'querydsl-jpa', version: "${querydslVersion}"
    kapt "com.querydsl:querydsl-apt:${querydslVersion}:jpa"
    kapt "org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final"
}

sourceSets {
    main.java.srcDirs += [file("$buildDir/generated/source/kapt/main")]
}
  • Querydsl이 타입 세이프를 보장하는 방법은 모든 @Entity 클래스에 대해 Q로 시작하는 전용 도메인 클래스를 생성하고 이를 통해서 쿼리를 코드 레벨에서 작성하는 것이다. 다행히도 위와 같이 기존에 제공되는 플러그인을 설정하여 도메인 클래스를 컴파일 타임에 자동 생성시킬 수 있다.
  • 전용 도메인 클래스는 /build/generated/source/kapt/main 디렉토리 이하에 패키지 단위로 자동 생성된다. sourceSets 옵션을 수정하여 생성 위치를 변경할 수 있다.

@Configuration

package com.jsonobject.example

import com.querydsl.jpa.impl.JPAQueryFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import javax.persistence.EntityManager
import javax.persistence.PersistenceContext

@Configuration
class QuerydslConfig(

    @PersistenceContext
    val entityManager: EntityManager
) {
    @Bean
    fun jpaQueryFactory(): JPAQueryFactory {

        return JPAQueryFactory(entityManager)
    }
}

@Repository

package com.jsonobject.example

import com.querydsl.core.Tuple
import com.querydsl.jpa.impl.JPAQueryFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport
import org.springframework.stereotype.Repository
import javax.annotation.Resource
import com.jsonobject.example.QFoo.foo as FOO
import com.jsonobject.example.QBar.bar as BAR

@Repository
class FooBarRepositorySupport(

    @Autowired
    @Resource(name = "jpaQueryFactory")
    val query: JPAQueryFactory

) : QuerydslRepositorySupport(FOO::class.java) {

    fun findAll(): List<Tuple> {

        return query.select(
                FOO.id,
                FOO.someField,
                BAR.id,
                BAR.someField
            )
            .from(FOO)
            .innerJoin(BAR)
            .on(BAR.fooId.eq(FOO.id))
            .fetch()
    }
}

참고 글

댓글
댓글쓰기 폼