Version v1.0 of the documentation is no longer actively maintained. The site that you are currently viewing is an archived snapshot. For up-to-date documentation, see the latest version.

トランザクション

概要

Komapperはトランザクション管理の高レベルAPIを提供します。

トランザクションの制御

Komapperが提供するトランザクション制御のためのAPIはJDBC版とR2DBC版で異なりますが見た目上のインターフェースは統一されています。 JdbcDatabaseもしくはR2dbcDatabaseが下記のようにdbという変数で宣言されていることを前提に説明を進めます。

val db = JdbcDatabase("jdbc:h2:mem:example;DB_CLOSE_DELAY=-1")
val db = R2dbcDatabase("r2dbc:h2:mem:///example;DB_CLOSE_DELAY=-1")

トランザクションの開始と終了

dbに定義されたwithTransaction関数の呼び出すことでトランザクションを開始できます。

db.withTransaction {
    ..
}

withTransaction関数にはトランザクション属性とトランザクションプロパティを指定できます。

db.withTransaction(
  transactionAttribute = TransactionAttribute.REQUIRES_NEW, 
  transactionProperty = TransactionProperty.IsolationLevel.SERIALIZABLE) {
    ..
}

トランザクション属性は以下の2種類のいずれかを指定できます。

REQUIRED
現在のトランザクションをサポートし、存在しない場合は新しいトランザクションを作成する
REQUIRES_NEW
新しいトランザクションを作成し、現在のトランザクションが存在する場合はそれを一時停止する

トランザクションプロパティは、様々なプロパティ要素を含むことができます。

IsolationLevel
トランザクション分離レベル
LockWaitTime
ロック待機時間
Name
トランザクションの名前
ReadOnly
トランザクションをリードオンリーモードで開始するかどうか

複数のトランザクションプロパティ要素を +演算子で1つのトランザクションプロパティにまとめることができます。

val property = TransactionProperty.IsolationLevel.SERIALIZABLE + TransactionProperty.Name("myTx") + TransactionProperty.ReadOnly(true)

withTransaction関数の呼び出しが終わるとトランザクションはコミットもしくはロールバックされます。

ロールバックされる条件は次のとおりです。

  • withTransaction関数の呼び出しが例外のスローにより終了する
  • withTransaction関数に渡されたラムダ式の中で明示的にロールバックを行う

ロールバックの条件に合致しない場合コミットされます。

明示的なロールバック

setRollbackOnly関数を呼び出すとwithTransaction関数終了時にロールバックが実行されます。

db.withTransaction { tx ->
    ..
    tx.setRollbackOnly()
    ..
}

すでにsetRollbackOnly関数を呼び出したかどうかはisRollbackOnly関数で確認できます。

db.withTransaction { tx ->
    ..
    if (tx.isRollbackOnly()) {
        ..
    }
    ..
}

新規トランザクションの開始と終了

すでに開始されたトランザクションの中で別のトランザクションを新しく開始するにはrequiresNew関数を呼び出します。

db.withTransaction { tx ->
    ..
    tx.requiresNew {
        ..
    }
    ..
}

requiresNew関数にはトランザクションプロパティを指定できます。

db.withTransaction { tx ->
    ..
    tx.requiresNew(transactionProperty = TransactionProperty.IsolationLevel.SERIALIZABLE) {
        ..
    }
    ..
}

requiresNew関数の呼び出しが終わるとトランザクションはコミットもしくはロールバックされます。

ロールバックされる条件は次のとおりです。

  • requiresNew関数の呼び出しが例外のスローにより終了する
  • requiresNew関数に渡されたラムダ式の中で明示的にロールバックを行う

ロールバックの条件に合致しない場合コミットされます。

トランザクショナルなFlow

R2dbcDatabaseはトランザクションを表すFlowを構築するためのflowTransaction関数を提供します。

val db = R2dbcDatabase("r2dbc:h2:mem:///example;DB_CLOSE_DELAY=-1")

val transactionalFlow: Flow<Address> = db.flowTransaction {
  val a = Meta.address
  val address = db.runQuery {
    QueryDsl.from(a).where { a.addressId eq 15 }.first()
  }
  db.runQuery {
    QueryDsl.update(a).single(address.copy(street = "TOKYO"))
  }
  val addressFlow = db.flowQuery {
    QueryDsl.from(a).orderBy(a.addressId)
  }
  emitAll(addressFlow)
}

// Transaction is executed
val list = transactionalFlow.toList()

上記の例では、flowTransactionの呼び出しはFlowを構築しているだけです。 トランザクションはtransactionalFlowを実際に使う際に初めて実行されます。

最終更新 March 11, 2022: Polish (5aa4b31)