티스토리 뷰

저번 글에서, Kotlin DSL로 JOOQ를 프로젝트에 적용시켜봤다.
2025.02.28 - [개발/SPRING] - Kotlin + SpringBoot에 JOOQ 적용기 - 1. 선택 이유와 코드 자동 생성하기
사실 사용법은 여기서 다룰 필요 없이 공식문서에서 굉장히 잘 다뤄주고 있다.
https://www.jooq.org/doc/latest/manual/sql-building/sql-statements/select-statement/

이번 포스팅에서는 그냥 내가 썼던 쿼리들을 몇개 가져와서 어떻게 썼나 소개해보려고 한다.
SELECT
fun findById(userId: String, projectId: String): Project {
return dsl.selectFrom(PROJECTS)
.where(PROJECTS.ID.eq(projectId)
.and(PROJECTS.CREATOR_ID.eq(userId)))
.fetchOneInto(Project::class.java)
?: throw NoSuchElementException("Project not found for given user.")
}
fun findByIds(userId: String, projectIds: List<String>): List<Project> {
return dsl.selectFrom(PROJECTS)
.where(PROJECTS.ID.`in`(projectIds)
.and(PROJECTS.CREATOR_ID.eq(userId)))
.fetchInto(Project::class.java)
}
PROJECT는 내가 커스텀하게 만든 객체인데 별다른 조치 없이 바로 매핑이된다. 물론 내가 조회한 데이터는 변수로 모두 들고 있어야한다.
SELECT COUNT
fun countById(userId: String, projectId: String): Boolean {
return dsl.selectCount()
.from(PROJECTS)
.where(PROJECTS.ID.eq(projectId)
.and(PROJECTS.CREATOR_ID.eq(userId)))
.fetchOne(0, Int::class.java) ?: 0
}
SELECT EXIST
fun existsNameByUserId(userId: String, name: String): Boolean {
return dsl.fetchExists(
dsl.selectOne()
.from(PROJECTS)
.where(
PROJECTS.CREATOR_ID.eq(userId)
.and(PROJECTS.NAME.eq(name))
)
)
}
이정도 쿼리들은 JPA로 바로 만들어져서 JPA와 혼용으로 쓰는게 좋겠다는 생각이 들었다. 간단한 SELECT 쿼리들만봐도 DSL이지만 비교적 퀄와 유사하다는걸 느낄 수 있었다.
INSERT
fun create(project: Project, id: String) {
dsl.insertInto(PROJECTS)
.set(PROJECTS.ID, id)
.set(PROJECTS.NAME, project.name)
.set(PROJECTS.CREATOR_ID, project.creatorId)
.set(PROJECTS.CREATED_AT, project.createdAt)
.execute()
}
fun create(project: Project) {
val record = PROJECTS.newRecord().from(project)
record.insert()
}
fun saveAll(projects: List<Project>) {
dsl.batchInsert(PROJECTS.newRecords(projects)).execute()
}
fun saveAll(projects: List<Project>) {
dsl.batchInsert(projects.map { project ->
dsl.newRecord(PROJECTS, project)
}).execute()
}
insertInto가 JPA와 다르게 확실히 편하다. saveAll도 간편하게 가능하다.
UDATE
fun update(project: Project) {
val result = dsl.update(PROJECTS)
.set(PROJECTS.NAME, project.name)
.set(PROJECTS.TYPE, project.type)
.set(PROJECTS.VERSION, project.version)
.set(PROJECTS.UPDATED_AT, LocalDateTime.now())
.where(PROJECTS.ID.eq(project.id).and(PROJECTS.CREATOR_ID.eq(project.creatorId)))
.execute()
}
fun update(project: Project) {
val record = PROJECTS.newRecord()
record.from(project)
val result = record.update()
}
fun moveTo(userId: String, targetParentId: String, ids: List<String>) {
dsl.update(PROJECTS)
.set(PROJECTS.PARENT_ID, targetParentId)
.where(PROJECTS.ID.`in`(ids).and(PROJECTS.CREATOR_ID.eq(userId)))
.execute()
}
개인적으로 JPA는 update가 불편하다고 생각한다. 명시적으로 save를 써야하고, setter만으로 처리되는 경우도 있다. 개인적으로는 너무 별로라 생각하고, 좀 괜찮은 방식인 DynamicUpdate는 entity에 붙는다.
JOOQ의 update는 누가봐도 update다. 컬럼별 업데이트도 진짜 쉽다.
DELETE
fun deleteByIds(ids: List<String>) {
dsl.deleteFrom(PROJECTS)
.where(PROJECTS.ID.`in`(ids))
.execute()
}
fun deleteById(id: String) {
dsl.deleteFrom(PROJECTS)
.where(PROJECTS.ID.eq(id))
.execute()
}
fun deleteOlderThan(dateTime: LocalDateTime) {
dsl.deleteFrom(PROJECTS)
.where(PROJECTS.CREATED_AT.lt(dateTime))
.execute()
}
CD는 JPA가 편하긴 한 것 같다.
마치며
개인적인 취향이지만 모든게 간소화된 JPA에 비해서 JOOQ의 명시적인 방식이 나한텐 좀 더 맞다. 그리고 DSL 형식이 상대적으로 덜한 것도 더 잘 맞았다.
다음 장은 뭘 써야 되는지 잘 모르겠지만, 트랜잭션 처리나 CTE 같은걸 알아보지 않을까 싶다.
'개발 > SPRING' 카테고리의 다른 글
스프링부트에서 AWS S3 객체 버전 관리 하기 (0) | 2025.03.30 |
---|---|
스프링부트에서 무조건 한번 실행하게 하기 (0) | 2025.03.07 |
Kotlin + SpringBoot에 JOOQ 적용기 - 1. 선택 이유와 코드 자동 생성하기 (0) | 2025.02.28 |
테스트를 도입하면서 느낀점과 고민들 (0) | 2024.08.14 |
SpringBoot에서 MultipartFile 전송하기 feat. FeignClient (1) | 2024.07.23 |
- Total
- Today
- Yesterday
- object
- MySQL
- 람다
- springboot
- S3
- AWS EC2
- docker
- AOP
- ChatGPT
- Elastic cloud
- Spring
- 스프링부트
- terraform
- 후쿠오카
- Kotlin
- AWS
- cache
- lambda
- JWT
- 티스토리챌린지
- serverless
- java
- GIT
- EKS
- OpenAI
- Log
- openAI API
- CloudFront
- 오블완
- elasticsearch
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |