Нет отката только для транзакции, когда исключение происходит в подметоде - PullRequest
6 голосов
/ 23 мая 2011

Я использую аннотации Hibernate + spring + @Transactional для обработки транзакций в моем приложении.

Менеджер транзакций объявляется следующим образом:

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

В большинстве случаев это работает хорошо, но я обнаружил проблему, когда у меня есть 2 метода, оба аннотированных @Transactional:

package temp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

public class OuterTestService {
    @Autowired
    private InnerTestService innerTestService;

    @Transactional
    public void outerMethod() {
        try {
            innerTestService.innerTestMethod();
        } catch (RuntimeException e) {
            // some code here
        }
    }
}

и

package temp;

import org.springframework.transaction.annotation.Transactional;

public class InnerTestService {

    @Transactional
    public void innerTestMethod() throws RuntimeException {
        throw new RuntimeException();
    }
}

Когда я вызываю OuterTestService # outerMethod (), я получаю исключение

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

Поскольку существует только одна транзакция (без вложенных транзакций), вся транзакция outerTestMethod() помечается как только для отката.

Я обнаружил, что могу легко преодолеть это, используя noRollbackFor:

package cz.csas.pdb.be.service.tempdelete;

import org.springframework.transaction.annotation.Transactional;

public class InnerTestService {

    @Transactional(noRollbackFor = RuntimeException.class)
    public void innerTestMethod() throws RuntimeException {
        throw new RuntimeException();
    }
}

Но это должно быть явно использовано в каждом методе. Поскольку эта ошибка не возникает во время тестов (которые откатываются), это неприемлемо.

Мой вопрос - есть ли способ автоматически (например, не явно для каждого метода) установить, что транзакции откатываются только при возникновении исключения из метода, который начал транзакцию (в данном случае, outerTestMethod())

Ответы [ 2 ]

11 голосов
/ 25 мая 2011

Создайте еще одну аннотацию, например, @NoRollbackTransactional, что-то вроде:

@Transactional(noRollbackFor = RuntimeException.class)
public @interface NoRollbackTransactional {
}

И используйте это в своих методах. С другой стороны, я согласен с комментарием Донала, вам следует пересмотреть границы своих транзакций, хотя, как правило, не очень хорошая идея вызывать @Transactional из другого @Transactional.

5 голосов
/ 26 июня 2012

Вам также может потребоваться отключить globalRollbackOnParticipationFailure .

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

Отключение флага участия решило это для меня:

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="globalRollbackOnParticipationFailure" value="false" />
    <property name="sessionFactory" ref="sessionFactory" />
</bean>
...