В нашем приложении мы используем монаду Either
для передачи сбоев.Согласно документам Jooq для управления транзакциями , для @Transactional
и DslContext.transaction
требуется сбросить Exception
для запуска отката транзакции.Мы бы предпочли зафиксировать или откатить транзакцию на основе состояния Either.
Псевдо-код того, что нам нужно, выглядит следующим образом:
public class DomainService {
private DSLContext dslContext;
public Either<SomeError, String> businessOperation() {
return transactional(configuration ->
firstDatabaseChange(configuration)
.flatMap(i -> secondDatabaseChange(configuration)));
}
private Either<SomeError, String> firstDatabaseChange(
DSLContext dslContext) {
//Mutate the Db in some way
}
private Either<SomeError, String> secondDatabaseChange(
DSLContext dslContext) {
//Mutate the Db in some way
}
/* How do we implement this method */
private Either<SomeError, String> transactional(Function<DSLContext,
Either<SomeError, String>> function) {
return function.apply(dslContext)
.onSuccess(i -> /*Commit the transaction */)
.onFailure(i -> /*Rollback the transaction*/);
}
}
У меня есть следующая рабочая реализацияtransactional
метода, который выглядит как взломать.(Интересно, что аннотация @Transactional
необходима для откатов, даже если мы не выкидываем никаких исключений).Есть ли лучший способ сделать это?
@Transactional
public <T> Either<SomeError, T> transactional(Function<DSLContext,
Either<SomeError, T>> function) {
Connection connection = dslContext.parsingConnection();
try {
connection.setAutoCommit(false);
Either<SomeError, T> either = function.apply(dslContext);
if (either.isSuccess()) {
connection.commit();
} else {
connection.rollback();
}
return result;
} catch (SQLException e) {
log.error("SqlException encountered", e);
return SomeError.failure(e);
} catch (Exception e) {
try {
connection.rollback();
} catch (SQLException e1) {
log.error("Exception encountered while rolling back", e1);
}
return SomeError.failure(e);
}
}