Querydsl

Spring을 사용하는 백엔드 개발자라면 Querydsl이라는 키워드를 많이 들어봤을 것이다. JPA를 사용하면 데이터베이스의 테이블을 Java 코드로 Entity를 만들어 관리하게 된다. Spring에서는 Spring Data JPA를 활용해서 기본적인 CRUD를 사용할 수 있지만 조금만 복잡해지면 JPQL을 사용해야 한다.

JPQL의 간단한 예시를 보자

Person(Entity)

@Entity
class Person(

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long? = null,

    @Column(name = "name")
    var name: String? = null,

    @Column(name = "age")
    var age: Int? = null,

    @Column(name = "job")
    var job: String? = null
)

PersonRepository

interface PersonRepository: JpaRepository<Person, Long> {
    @Query("select p.id from Person p where p.age between :from and :to")
    fun findIdByAgeBetween(@Param("from") from: Int, @Param("to") to: Int)
}

@Query 어노테이션을 활용하면 nativeQuery 옵션을 true로 줘서 SQL도 사용할 수 있지만 생략하거나 false로 준다면 JPQL을 사용할 수 있다.

전반적으로 JPQL은 문자열로 작성되기 때문에 사람이 작성하는 특성 상 오타가 없을 거라는 확신은 가질 수 없다. 위 예제에서는 나이가 from과 to 사이인 사람의 id를 조회하는 메서드인데 파라미터 바인딩 시 :from 대신 :fron으로 들어갈 수도 있고, 이는 컴파일 오류를 내지 않기 때문에 런타임 시점에 해당 메서드가 사용될 때 잘못 됐다는 것을 알 수 있다. 그리고 이 예제는 정적 쿼리이기 때문에 간단하게 보일 수 있다. 동적 쿼리를 JPQL로 짠다면 코드가 복잡해진다. (사람마다 다르겠지만 내 기준으로는 가독성이 떨어져 보인다.)

Querydsl 장점

  • 문자열이 아닌 Java 코드로 쿼리를 작성할 수 있다.
  • 컴파일 시점에 오류를 확인할 수 있다.
  • 동적 쿼리 작성이 용이하다.

이러한 이점으로 많은 사람들이 Querydsl을 사용한다.

Querydsl 설정

Kotlin, Spring Boot 기준으로 예제 코드를 준비했다.

개발 환경

  • Kotlin / Spring Boot
  • Gradle (Kotlin dsl)

build.gradle.kts

plugins {
    id("org.springframework.boot") version "2.7.3"
    id("io.spring.dependency-management") version "1.0.13.RELEASE"
    kotlin("jvm") version "1.6.21"
    kotlin("plugin.spring") version "1.6.21"
    kotlin("plugin.jpa") version "1.6.21"
    kotlin("kapt") version "1.6.21" // kapt 추가
}

...

// querydsl version
val querydslVersion = "5.0.0"

dependencies {
    ...

    // querydsl
    implementation("com.querydsl:querydsl-jpa:$querydslVersion")
    kapt("com.querydsl:querydsl-apt:$querydslVersion:jpa")
}

KAPT
이 프로젝트는 Kotlin을 사용하기 때문에 컴파일을 javac로 하지 않고 kotlinc로 컴파일한다. 따라서 Java로 작성 된 Annotation Processor가 동작하지 않고, Kotlin에서는 KAPT(Kotlin Annotation Precessing Tool)을 사용한다.

QuerydslConfiguration

@Configuration
class QuerydslConfiguration {

    @PersistenceContext
    private lateinit var entityManager: EntityManager

    @Bean
    fun jpaQueryFactory(): JPAQueryFactory {
        return JPAQueryFactory(entityManager)
    }
}


gradle의 compileKotlin을 해보면

querydsl1

Q파일이 build/generated/source/kapt/... 경로에 생성되었다.

사용 하는 방법은 다음 게시글에서!