🖲️

Micronaut + jOOQでトランザクション管理

2021/02/04に公開
  • Micronaut: 2.3.1
  • jOOQ: 3.14.7
  • Kotlin: 1.4.21

使用するテーブル

customerテーブル -> customer_detailテーブルの順でINSERTする処理で試す。

トランザクション管理なし

customer_detailテーブルのINSERTに失敗した場合に、先にINSERTしたcustomerテーブルはロールバックされない。

@Singleton
class CustomersService(
    private val dslContext: DSLContext
) {

    fun add(name: String) {
        val id = Random.nextInt()
        dslContext
            .insertInto(CUSTOMER, CUSTOMER.ID, CUSTOMER.CREATED_AT)
            .values(id, LocalDateTime.now())
            .execute()

        dslContext
            .insertInto(CUSTOMER_DETAIL, CUSTOMER_DETAIL.CUSTOMER_ID, CUSTOMER_DETAIL.NAME, CUSTOMER_DETAIL.CREATED_AT)
            .values(id, name, LocalDateTime.now())
            .execute()
    }
}

DSLContex#transactionを使用する

こちらは期待通りトランザクション管理される。

@Singleton
class CustomerService(
    private val dslContext: DSLContext
) {
    fun add(name: String) {
        dslContext.transaction { c ->
            val id = Random.nextInt()
            DSL.using(c)
                .insertInto(CUSTOMER, CUSTOMER.ID, CUSTOMER.CREATED_AT)
                .values(id, LocalDateTime.now())
                .execute()

            DSL.using(c)
                .insertInto(
                    CUSTOMER_DETAIL,
                    CUSTOMER_DETAIL.CUSTOMER_ID,
                    CUSTOMER_DETAIL.NAME,
                    CUSTOMER_DETAIL.CREATED_AT
                )
                .values(id, name, LocalDateTime.now())
                .execute()
        }
    }
}

https://www.jooq.org/doc/3.1/manual/sql-execution/transaction-management/

@TransactionalAdviceを使用する

TransactionalAdviceアノテーションを利用してトランザクション管理ができる。
SpringのTransactionalアノテーションと同様と考えればOK。

Gradleを使用してる場合、dependenciesに以下を追加する。

dependencies {
    ...
    implementation 'io.micronaut.data:micronaut-data-tx'
}

TransactionalAdviceアノテーションを使用する場合はclassとメソッドをopenにする必要がある。
なお読み取り専用のReadOnlyアノテーションも用意されている。

@Singleton
open class CustomersService(
    private val dslContext: DSLContext
) {

    @TransactionalAdvice
    open fun add(name: String) {
        val id = Random.nextInt()
        dslContext
            .insertInto(CUSTOMER, CUSTOMER.ID, CUSTOMER.CREATED_AT)
            .values(id, LocalDateTime.now())
            .execute()

        dslContext
            .insertInto(CUSTOMER_DETAIL, CUSTOMER_DETAIL.CUSTOMER_ID, CUSTOMER_DETAIL.NAME, CUSTOMER_DETAIL.CREATED_AT)
            .values(id, name, LocalDateTime.now())
            .execute()
    }
}

Discussion