일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Spring Data JPA
- spring
- API
- spring kafka
- CodePipeline
- mirror maker2
- JPA
- kafka
- Streams
- consumer
- centos7
- git
- ECS
- offsetdatetime
- bean
- Kubernetes
- Entity
- cd
- K8s
- QueryDSL
- PAGING
- Spring JPA
- transactionaleventlistener
- topic생성
- Kotlin
- AWS
- producer
- CI
- mysql
- entity graph
- Today
- Total
Yebali
QueryDSL in Kotlin 본문
QueryDSL이란?
기존 JPA Criterial는 코드로 JPQL을 작성하므로 문법 오류를 컴파일 단계에서 잡을 수 있고 IDE 자동완성 기느의 도움을 받을 수 있는 등 여러 가지 장점이 있다. 하지만 너무 복잡하고 어렵다.
쿼리를 문자가 아닌 코드로 작성해도 쉽고 간결하며 그 모양도 쿼리와 비슷하게 개발 할 수 있는 프로젝트가 바로 QueryDSL이다.
QueryDSL 설정
build.gradle.kts에 아래 설정을 추가해준다. Version은 개발자가 원하는 버전을 선택한다.
plugins {
kotlin("kapt") version "1.4.32"
}
dependencies {
val querydslVersion = "4.4.0"
//== QueryDSL ==//
implementation("com.querydsl:querydsl-jpa:$querydslVersion") // QueryDSL JPA 라이브러리
kapt("com.querydsl:querydsl-apt:$querydslVersion:jpa") // Q클래스 생성에 필요한 라이브러리
}
QueryDSL은 @Entity 애노테이션을 선언한 클래스를 탐색하고, JPA Annotation Processor를 이용하여 Q 클래스를 생성한다. 이때 Annotation Processor를 사용하기 위해서 ‘kapt’라는 플러그인을 사용한다.
Kapt란?
코틀린 프로젝트를 컴파일 할 때는 javac가 아닌 kotlinc로 컴파일을 하기 때문에 Java로 작성한 애노테이션 프로세서가 동작하지 않는다. 그렇기 때문에 코틀린에서는 이러한 애노테이션 처리기를 위해 KAPT(Kotlin Annotation Processing Tool)를 제공한다.
이후 Gradle을 Reload하고 build 하면 ‘build/generated/source/japt/main’ 하위에 @Entity 애노테이션이 붙어있던 클래스로부터 Q 클래스들이 생성된 걸 볼 수 있다.
Option) JpaQueryFactory Bean으로 등록하기
QueryDSL는 이용해 쿼리를 만들고 실행시키는 기능은 JpaQueryFactory를 통해 이루어진다.
이때 JpaQueryFactory를 Bean으로 등록하여 필요한 곳에서 주입 받아 쓰면 편리하다.
// QuerydlsConfig.kt
@Configuration
class QuerydslConfig(
@PersistenceContext
private val entityManager: EntityManager
) {
@Bean
fun jpaQueryFactory() = JPAQueryFactory(entityManager)
}
QueryDSL 사용
QueryDSL을 사용하기 위해서는 쿼리 타입(Q)을 생성해야 하는데 생성자는 별칭을 파라미터로 받는다.
지정한 별칭은 JPQL에서 사용된다.
QTeam qteam = new QTeam("t") // 생성되는 JPQ의 별칭이 't'
하지만 쿼리 타입(Q)은 사용하기 편히하도록 내부에 기본 인스턴스를 보관하고 있다.
@Generated("com.querydsl.codegen.EntitySerializer")
public class QTeam extends EntityPathBase<Team> {
private static final long serialVersionUID = 997838414L;
public static final QTeam team = new QTeam("team"); // 내부에 이미 인스턴스가 있음.
...
...
}
그렇기 때문에 내부에 있는 인스턴스를 그대로 쓰면 된다.
QTeam qteam = QTeam.team // 이렇게 쓰거나
OR
import com.example.testKoSpring.entity.QTeam.team
QTeam qteam = team
밑에 나올 예제에서는 QTeam.team를 import해서 사용할 것이다.
조회
- 여러건 조회 : fetch()
fun findAll(): MutableList<Team>? { return jpaQueryFactory .selectFrom(team) .fetch() }
- 단건 조회 : fetchOne()
fun fundOne(teamId: Long): Team? { return jpaQueryFactory .selectFrom(team) .where(team.id.eq(teamId)) .orderBy(team.teamName.desc()) .fetchOne() }
페이징
fun fundPaging(): MutableList<Team>? {
return jpaQueryFactory
.selectFrom(team)
.offset(0) // page number
.limit(3) // paging size
.orderBy(team.teamName.desc())
.fetch()
}
Group By
fun group(): MutableList<Team>? {
return jpaQueryFactory
.selectFrom(team)
.groupBy(team.teamName)
.having(team.id.gt(100))
.fetch()
}
groupBy후 그룹화된 결과를 제한하려면 having을 사용하면 된다.
조인
- 기본 조인
fun join(): MutableList<Team>? { return jpaQueryFactory .selectFrom(team) .leftJoin(team.members) .fetch() } //== on 사용 ==// fun joinOn(): MutableList<Team>? { return jpaQueryFactory .selectFrom(team) .leftJoin(team.members) .on(team.id.gt(2)) .fetch() }
- 기본 조인시 쿼리
select team0_.id as id1_1_, team0_.team_name as team_nam2_1_ from team team0_ left outer join member members1_ on team0_.id=members1_.team //== on 사용 ==// select team0_.id as id1_1_, team0_.team_name as team_nam2_1_ from team team0_ left outer join member members1_ on team0_.id=members1_.team and ( team0_.id>? )
- 페치 조인
fun join(): MutableList<Team>? { return jpaQueryFactory .selectFrom(team) .leftJoin(team.members).fetchJoin() //해당 조인이 페치 조인임을 명시 .fetch() }
- 페치 조인시 쿼리
select team0_.id as id1_1_0_, members1_.id as id1_0_1_, team0_.team_name as team_nam2_1_0_, members1_.name as name2_0_1_, members1_.team as team3_0_1_, members1_.team as team3_0_0__, members1_.id as id1_0_0__ from team team0_ left outer join member members1_ on team0_.id=members1_.team
서브 쿼리
JPAExpressions를 이용해서 서브 쿼리를 적용할 수 있다.
서브 쿼리는 select, where 절 안에만 사용할 수 있다.
fun subQuery(): Team? {
return jpaQueryFactory
.selectFrom(team)
.where(team.id.eq(
JPAExpressions
.select(team.id.max())
.from(team)
))
.fetchOne()
}
서브 쿼리 사용 시 쿼리
select
team0_.id as id1_1_,
team0_.team_name as team_nam2_1_
from
team team0_
where
team0_.id=(
select
max(team1_.id)
from
team team1_
)
'Spring' 카테고리의 다른 글
Spring의 Filter와 Interceptor (0) | 2022.01.23 |
---|---|
Join의 종류와 QueryDsl (0) | 2021.11.01 |
Spring JPA의 Cache (0) | 2021.10.31 |
Spring JPA에 기본 생성자가 필요한 이유 (0) | 2021.10.31 |
Spring JPA의 @OneToOne 관계와 지연로딩 (0) | 2021.10.11 |