почему транзакция откатывается на RuntimeException, но не на SQLException - PullRequest
23 голосов
/ 19 августа 2011

У меня есть метод службы, управляемый Spring, для управления вставками базы данных. Он содержит несколько операторов вставки.

@Transactional
public void insertObservation(ObservationWithData ob) throws SQLException 
{
    observationDao.insertObservation(ob.getObservation());
            // aop pointcut inserted here in unit test
    dataDao.insertData(ob.getData());
}

У меня есть два модульных теста, которые выдают исключение перед вызовом второй вставки. Если исключением является RuntimeException, транзакция откатывается. Если исключение - SQLException, первая вставка сохраняется.

Я сбит с толку. Может кто-нибудь сказать мне, почему транзакция не откатывается на SQLException? Может кто-нибудь предложить предложение, как справиться с этим? Я мог бы поймать SQLException и выдать RuntimeException, но это кажется странным.

Ответы [ 3 ]

41 голосов
/ 19 августа 2011

Это определенное поведение. Из документов :

Любой RuntimeException запускает откат, а любое проверенное исключение - нет.

Это обычное поведение для всех API транзакций Spring. По умолчанию, если из кода транзакции выдается RuntimeException, транзакция будет откатываться. Если выброшено исключение (то есть не RuntimeException), транзакция не будет откатываться.

Основанием для этого является то, что Spring обычно использует RuntimeException классы для обозначения неисправимых состояний ошибки.

Это поведение можно изменить по умолчанию, если вы хотите это сделать, но то, как это сделать, зависит от того, как вы используете Spring API и как вы настроили свой менеджер транзакций.

2 голосов
/ 19 августа 2011

Spring широко использует RuntimeExceptions (включая использование DataAccessExceptions для обертывания SQLExceptions или исключений из ORM) для случаев, когда восстановление не происходит после исключения.Предполагается, что вы хотите использовать проверенные исключения для случаев, когда слой выше службы должен быть уведомлен о чем-то, но вы не хотите, чтобы транзакция вмешивалась.

Если вы используете Spring, вы также можете использовать его библиотеки jdbc-wrapping и DataAccessException-средство перевода, это сократит объем кода, который вы должны поддерживать, и предоставит более значимые исключения.Также плохой запах имеет наличие сервисного уровня, выдающего специфические для реализации исключения.Пред-Spring способ заключался в создании проверенных исключений, не зависящих от реализации, обертывающих специфичные для реализации исключения, что приводило к большой загруженности работой и раздутой базе кода.Путь Spring избегает этих проблем.

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

1 голос
/ 02 августа 2018

Для @Transactional по умолчанию откат происходит во время выполнения, только непроверенные исключения. Таким образом, ваше проверенное исключение SQLException не вызывает откат транзакции; поведение можно настроить с помощью параметров аннотаций rollbackFor и noRollbackFor.

@Transactional(rollbackFor = SQLException.class)
public void insertObservation(ObservationWithData ob) throws SQLException 
{
    observationDao.insertObservation(ob.getObservation());
            // aop pointcut inserted here in unit test
    dataDao.insertData(ob.getData());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...