Элегантный способ присоединиться к транзакциям в Reactive Vert.X

Допустим, у меня есть метод обслуживания, в котором я выполняю некоторые проверки / повторные вызовы и т. Д. (Например, someServiceMethod2 in) и хочу сделать его безопасным для транзакций. У меня также есть repoMethod, который включает транзакцию. Как я могу откатить дочернюю транзакцию, если родительская транзакция выдает исключение?

Есть ли способ объединить эти два метода в транзакции? Так же, как то, что распространение будет выполняться в Spring lib.

      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
                 }
        }
    }
}
Другие вопросы по тегам