UnexpectedRollbackException - полный анализ сценария - PullRequest
18 голосов
/ 05 января 2010

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

Из документации Spring:

Выдается, когда попытка совершить транзакцию привела к неожиданному откату

Я хочу понять раз и навсегда

  1. Что именно вызывает его?

    • Где произошел откат? в коде сервера приложений или в базе данных?
    • Было ли это вызвано из-за определенного основного исключения (например, что-то из java.sql. *)?
    • Это связано с Hibernate? Это связано с Spring Transaction Manager (не JTA в моем случае)?
  2. Как этого избежать? Есть ли лучший способ избежать этого?

  3. Как его отладить? кажется, что это трудно воспроизвести, какие-нибудь проверенные способы его устранения?

Ответы [ 3 ]

11 голосов
/ 09 января 2010

Я нашел, что это отвечает на остальную часть вопроса: https://jira.springsource.org/browse/SPR-3452

Я думаю, что мы должны дифференцировать между «логическими» областями транзакций и «физические» транзакции здесь ...

PROPAGATION_REQUIRED создает объем логической транзакции для каждого метод, к которому он применяется. каждый такая логическая область транзакции может индивидуально выбрать только откат статус, с внешней транзакцией сфера логически независима от внутренняя область транзакции. из конечно, в случае стандартного PROPAGATION_REQUIRED поведение, они будет сопоставлен с тем же физическим сделка. Таким образом, маркер только для отката установить во внутренней области транзакции влияет на внешнюю транзакцию шанс на самом деле совершить. Тем не мение, поскольку объем внешней транзакции сделал не решаться на сам откат откат (молча срабатывает внутренняя область транзакции) неожиданно на этом уровне - что почему UnexpectedRollbackException получает бросок.

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

PROPAGATION_NESTED снова отличается в том, что он использует один физический транзакция с несколькими точками сохранения что он может откатиться к. Такой частичный откаты позволяют внутреннюю транзакцию объем, чтобы вызвать откат для его сфера, с внешней транзакцией возможность продолжить физическое транзакция, несмотря на некоторые операции откатился назад. Это как правило, отображаются на точки сохранения JDBC, так будет работать только с ресурсом JDBC транзакции (весна DataSourceTransactionManager).

Для завершения обсуждения: Неожиданное исключение Rollback может также быть брошенным без заявления когда-либо установив маркер только для отката сам. Вместо транзакции инфраструктура, возможно, решила, что единственный возможный результат откат из-за ограничений в текущее состояние транзакции. Это особенно актуально с XA сделки.

Как я и предлагал выше, бросая исключение при внутренней транзакции объем, а затем поймать это исключение в внешняя сфера и перевод в тихий вызов setRollbackOnly там должно работать для вашего сценария. вызывающая сторона внешней транзакции никогда не вижу исключения тогда. С вами беспокоиться только о таких тихих откатах из-за особых требований навязанный абонентом, я бы даже утверждают, что правильный архитектурный Решение состоит в том, чтобы использовать исключения в уровень обслуживания, и переводить эти исключения в бесшумные откаты на уровне фасада сервиса (справа прежде чем вернуться к этому специальному вызывающий абонент).

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

Юрген

8 голосов
/ 05 января 2010

Прокрутите немного назад в журнале (или увеличьте его размер буфера), и вы увидите, что именно вызвало исключение.

Если этого не происходит, проверьте методы getMostSpecificCause() и getRootCause() для UnexpectedRollbackException - они могут быть полезны.

4 голосов
/ 10 апреля 2012

Хорошо, я могу рассказать вам, как воспроизвести исключение UnexpectedRollbackException. Я работал над своим проектом, и я получил это UnexpectedRollbackException в следующей ситуации. В моем проекте есть уровни контроллера, сервиса и dao. То, что я сделал, в моем классе уровня обслуживания,

class SomeServiceClass {
    void outerTransaction() {
        // some lines of code
        innerTransaction();
        //AbstractPlatformTransactionManager tries to commit but UnexpectedRollbackException is thrown, not here but in controller layer class that uses SomeServiceClass.
    }

    void innerTransaction() {
        try {
            // someDaoMethod or someDaoOperation that throws exception
        } catch(Exception e) {
            // when exception is caught, transaction is rolled back, outer transaction does not know about it.
            // I got this point where inner transaction gets rolled back when I set HibernateTransactionManager.setFailEarlyOnGlobalRollbackOnly(true)
            // FYI : use of following second dao access is wrong, 
            try {
                // again some dao operation
            } catch(Exception e1) {
                throw e2;
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...