강의

멘토링

로드맵

Inflearn brand logo image

인프런 커뮤니티 질문&답변

이강현님의 프로필 이미지
이강현

작성한 질문수

실전 jOOQ! Type Safe SQL with Java

insert 문을 통한 데이터 생성

generate dao 를 통한 삽입 시 pk auto-increment 가 적용되지 않습니다

해결된 질문

작성

·

52

·

수정됨

1

Kotlin, Groovy gradle, PostrgreSQL 기반으로 프로젝트 세팅이 되어 있습니다

 

@Repository
class ActorRepository(
    private val dsl: DSLContext,
    configuration: Configuration
) {
    private val actorDao = ActorDao(configuration)

    companion object {
        private val ACTOR = JActor.ACTOR
    }

    fun save(actor: Actor): Unit = actorDao.insert(actor)

}

이러한 방식으로 Repository 가 구현되어 있을 때,

 

@SpringBootTest
class ActorRepositoryTest(
    private val actorRepository: ActorRepository,
): StringSpec({

    "insert test" {
        val actor = Actor().apply {
            firstName = "John"
            lastName = "Doe"
        }

        println("Actor before insert: $actor")

        val insertedActor = actorRepository.save(actor)
    }

}) {
    override fun extensions() = listOf(SpringExtension)
}

 

image.pngimage.png

위 쿼리가 실행됩니다

제가 예상했던 insert into "actor" ("first_name", "last_name") values(?, ?) 과는 다르게 id 값이 0으로 고정되어 생성되더라구요

generate dao 를 생성하는 방법이 잘못된 걸까요?

답변 1

2

설동민님의 프로필 이미지
설동민
지식공유자

이강현님 안녕하세요. 저도 궁금해서 로컬에서 코틀린으로 테스트해봤는데요.

코틀린의 경우, 로그에서만 auto increment 컬럼이 0으로 찍히고 정상적으로 동작하는것으로 보입니다. (신기하네요..?)

 

스크린샷 2025-08-09 오후 3.24.05.png.webp

 

참고로 kotlin으로 jOOQ를 사용하는 경우

코틀린 전용 generator를 사용하셔야합니다.

 

아래 링크 참고 부탁드립니다.

https://www.jooq.org/doc/latest/manual/code-generation/codegen-output-languages/kotlingenerator/

 

아래는 제가 테스트했을때 사용한 build.gradle 설정입니다.

('섹션 5. jOOQ 고급 - 다양한 방식으로 jOOQ DSL 만들기'에 있는 testcontainer + flyway 설정을 변형해서 사용했습니다.)

 

import org.jooq.meta.jaxb.*

buildscript {
    ext {
        jooqVersion = '3.19.5'
    }
}

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.3'
    id 'io.spring.dependency-management' version '1.1.4'
    id 'dev.monosoul.jooq-docker' version '6.0.14'
    id "org.jetbrains.kotlin.jvm" version "1.9.24"
    id "org.jetbrains.kotlin.plugin.spring" version "1.9.24"
}

group = 'org.sight'
version = '0.0.1-SNAPSHOT'

java {
}

repositories {
    mavenCentral()
}

sourceSets {
    main {
        java {
            srcDirs = ["src/main/java", "src/generated"]
        }
    }
}


jooq {
    version = "${jooqVersion}"
    withContainer {
        image {
            name = "mysql:8.0.29"
            envVars = [
                    MYSQL_ROOT_PASSWORD: "passwd",
                    MYSQL_DATABASE     : "sakila"
            ]
        }

        db {
            username = "root"
            password = "passwd"
            name = "sakila"
            port = 3306
            jdbc {
                schema = "jdbc:mysql"
                driverClassName = "com.mysql.cj.jdbc.Driver"
            }
        }
    }
}

tasks {
    generateJooqClasses {
        schemas.set(["sakila"])
        outputDirectory.set(project.layout.projectDirectory.dir("src/generated"))
        includeFlywayTable.set(false)

        usingJavaConfig {
            withName('org.jooq.codegen.KotlinGenerator')
            generate = new Generate()
                    .withJavaTimeTypes(true)
                    .withDeprecated(false)
                    .withDaos(true)
                    .withFluentSetters(true)
                    .withRecords(true)
                    .withKotlinNotNullPojoAttributes(true) // NOT NULL 컬럼은 Kotlin의 Non-Null 타입으로 생성 (PK 제외)
                    .withKotlinNotNullRecordAttributes(true) // NOT NULL 컬럼은 Kotlin의 Non-Null 타입으로 생성 (PK 제외)

            withStrategy(
                    new Strategy().withName("jooq.custom.generator.JPrefixGeneratorStrategy")
            )

            database.withForcedTypes(
                    new ForcedType()
                            .withUserType("java.lang.Long")
                            .withTypes("int unsigned"),
                    new ForcedType()
                            .withUserType("java.lang.Integer")
                            .withTypes("tinyint unsigned"),
                    new ForcedType()
                            .withUserType("java.lang.Integer")
                            .withTypes("smallint unsigned")
            )
        }
    }
}

dependencies {
    implementation "org.jooq:jooq:${jooqVersion}"

    implementation 'org.springframework.boot:spring-boot-starter'
    implementation('org.springframework.boot:spring-boot-starter-jooq') {
        exclude group: 'org.jooq'
    }

    runtimeOnly 'com.mysql:mysql-connector-j'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'

    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'

    jooqCodegen project(':jooq-custom')
    jooqCodegen "org.jooq:jooq:${jooqVersion}"
    jooqCodegen "org.jooq:jooq-meta:${jooqVersion}"
    jooqCodegen "org.jooq:jooq-codegen:${jooqVersion}"

    jooqCodegen 'org.flywaydb:flyway-core:10.8.1'
    jooqCodegen 'org.flywaydb:flyway-mysql:10.8.1'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
}

tasks.named('test') {
    useJUnitPlatform()
}
kotlin {
    jvmToolchain(17)
}
이강현님의 프로필 이미지
이강현

작성한 질문수

질문하기