Есть ли способ программно откатить транзакции в JooQ? - PullRequest
0 голосов
/ 07 июня 2018

В нашем приложении мы используем монаду 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);
    }
}

1 Ответ

0 голосов
/ 07 июня 2018

Как упомянул Лукас Седер , процедурный API находится на дорожной карте Jooq: github.com/jOOQ/jOOQ/issues/5376

Пока это не выпущено, вы можете достичь требуемогоповедение, как показано ниже:

public <T> Either<SomeError, T> transactional(Function<DSLContext,
        Either<SomeError, T>> function) {
    return dslContext.connectionResult(connection -> {
        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);
        }
    });
}
...