Элегантный способ присоединиться к транзакциям в Reactive Vert.X
Допустим, у меня есть метод обслуживания, в котором я выполняю некоторые проверки / повторные вызовы и т. Д. (Например, someServiceMethod2 in) и хочу сделать его безопасным для транзакций. У меня также есть repoMethod, который включает транзакцию. Как я могу откатить дочернюю транзакцию, если родительская транзакция выдает исключение?
Есть ли способ объединить эти два метода в транзакции? Так же, как то, что
fun someServiceMethod () {
client.withTransaction { c ->
val bla = someServiceMethod2() // works
someRepo.doSthRepoStuff(bla)) // works
throw Exception("Just for test purpose") // crashes -> should also rollback transaction from doSthRepoStuff
}
}
...
fun doSthRepoStuff(bla : String) {
client.withTransaction { c ->
// do db related stuff here
}
}
Единственный способ сделать это прямо сейчас - использовать только транзакцию службы и передать соединение методу репо. Мне это почему-то кажется странным (чтобы предоставить методу репо соединение sql)
Есть ли элегантный способ решить эту проблему?
2 ответа
Потратил много времени, чтобы понять это, и единственный способ добиться этого - передать объект следующего класса
io.vertx.reactivex.sqlclient.SqlConnection
И это работало довольно гладко.
Вы можете использовать функциональный блок с параметром:
fun someServiceMethod() {
client.withTransaction(TransactionPropagation.CONTEXT) { c ->
val bla = someServiceMethod2() // works
someRepo.doSthRepoStuff(bla)) // works
throw Exception("Just for test purpose") // crashes -> should also rollback transaction from doSthRepoStuff
}
}
...
fun doSthRepoStuff(bla : String) {
client.withTransaction(TransactionPropagation.CONTEXT) { c ->
// do db related stuff here
}
}
Таким образом, если в текущем контексте нет запущенной транзакции, она будет инициирована и распространена на все последующие вызовы БД, даже во внедренных компонентах.
Просто имейте в виду, что все вызовыwithTransaction()
во всех бобах должен бытьTransactionPropagation.CONTEXT
аргумент. Чтобы получить ссылку на клиент БД, вы просто добавляете экземплярPgPool
в каждом компоненте как обычно:
@ApplicationScoped
class Bean1 {
@Inject
lateinit var client: PgPool
fun doStuff1(): Uni<Void> {
return client.withTransaction(TransactionPropagation.CONTEXT) { c ->
// DB related calls using an existing TX
// or creating a new one if absent
}
}
}
@ApplicationScoped
class Bean2 {
@Inject
lateinit var client: PgPool
@Inject
lateinit var bean1: Bean1
fun doStuff2(): Uni<Void> {
// Start a new TX
return client.withTransaction(TransactionPropagation.CONTEXT) { c ->
// Bean1's DB calls will use this just created transaction
bean1.doStuff1()
.onItem.transform { _ ->
// DB related calls using the existing TX
}
}
}
}