Поведение весенних транзакций - PullRequest
0 голосов
/ 15 мая 2018

Кажется, что когда метод транзакционной пружины с распространением NESTED вызывает другой транзакционный метод с распространением ТРЕБУЕТСЯ, внутренняя транзакция может вызвать откат внешней логической транзакции.Кто-нибудь может подтвердить?

Я хотел бы обработать RuntimeException и не откатывать внешнюю транзакцию, например:

@Transactional
class A {

    @Autowired
    B b;

    @Autowired
    C c;

    void methodA() { // outer transaction, this should not be rollback but currently getting UnexpectedRollbackException
        b.methodB(() -> c.methodC());
    }
}

@Transactional(propagation = Propagation.NESTED)
class B {

    void methodB(Runnable action) { // inner nested transaction
        try{
            action.run();
        } catch (Exception e){
           // nothing
        }
    }
}

@Transactional
class C {
    void methodC() { // inner required transaction
        throw new RuntimeException();
    }
}

1 Ответ

0 голосов
/ 15 мая 2018

Почему бы и нет?Распространение NESTED начинает транзакцию внутри текущей, если она существует, и ведет себя как REQUIRED в противном случае.Состояние javadocs:

/**
 * Support a current transaction; create a new one if none exists.
 * Analogous to the EJB transaction attribute of the same name.
 * <p>This is typically the default setting of a transaction definition,
 * and typically defines a transaction synchronization scope.
 */
int PROPAGATION_REQUIRED = 0;

/**
 * Execute within a nested transaction if a current transaction exists,
 * behave like {@link #PROPAGATION_REQUIRED} else. There is no analogous
 * feature in EJB.
 * <p><b>NOTE:</b> Actual creation of a nested transaction will only work on
 * specific transaction managers. Out of the box, this only applies to the JDBC
 * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
 * when working on a JDBC 3.0 driver. Some JTA providers might support
 * nested transactions as well.
 * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
 */
int PROPAGATION_NESTED = 6;

Следует отметить, что NESTED действительно поддерживается, только если ваш драйвер JDBC поддерживает точки сохранения.Это означает:

No existing transaction
A (NESTED)
B (REQUIRED)

будет иметь следующее поведение:

begin; -- called prior to A but in A's 
A.doSomething();
B.doSomethingThatCausesException()
rollback;

и

Existing transaction
A (NESTED)
B (REQUIRED)

будет иметь следующее поведение:

begin; -- called outside of the scope of A
savepoint A_savepoint
A.doSomething();
B.doSomethingThatCausesException();
rollback A_savepoint;

, если ваш драйвер JDBC поддерживает вложенные транзакции.В противном случае это будет вести себя как первый сценарий.См. Также этот ответ.

Тем не менее, я считаю, что точки сохранения - это больше проблем, чем они стоят, и вы избавите себя от множества потенциальных проблем, если будете лечить любую из вашихОперации с базой данных атомарно.

...