почему транзакция откатывается на RuntimeException, но не на SQLException

У меня есть управляемый 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, но это кажется странным.

25
задан climmunk 19 August 2011 в 18:30
поделиться

3 ответа

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

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

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

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

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

42
ответ дан 28 November 2019 в 20:57
поделиться

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

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

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

2
ответ дан 28 November 2019 в 20:57
поделиться

Для @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());
}
3
ответ дан 28 November 2019 в 20:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: