TL;DR
-
TransactionalOperator.transactional
を使うと簡単- 処理の中での
suspend
関数呼び出しはmono
関数でラップするのが簡単
- 処理の中での
やり方
サンプルコードは以下の通りです。
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.reactor.awaitSingle
import kotlinx.coroutines.reactor.mono
import org.springframework.stereotype.Component
import org.springframework.transaction.reactive.TransactionalOperator
@Component
class TransactionOperation(private val transactionalOperator: TransactionalOperator) {
// 中にそのまま処理を書く場合
suspend fun operation() {
transactionalOperator
.transactional(
mono {
/* ここにやりたい処理(DBアクセスを行うsuspend関数の呼び出しなど)を書く */
}
).awaitSingle()
}
}
Kotlin
から扱いやすくするため、以下のようなutil
を用意するのもおすすめです。
// Tそのものは上界無指定 = nullableだが、awaitSingleOrNullがT?を返してしまうため、キャストしている
@Suppress("UNCHECKED_CAST")
suspend fun <T> TransactionalOperator.transactional(block: suspend CoroutineScope.() -> T): T =
transactional(mono(block = block)).awaitSingleOrNull() as T
// 以下のように利用できる
suspend fun foo() { /* トランザクション内で実行したい処理 */ }
suspend fun bar() {
// トランザクションを有効にしてfooを呼び出す
transactionalOperator.transactional { foo() }
}
TransactionalOperatorの取得について
TransactionalOperator
は、自分の環境ではAutowire
して利用できました。
また、ReactiveTransactionManager
から生成することもできます。