У меня есть следующий странный сценарий с управлением транзакциями пружины:
У меня есть метод, который называет метод B, который называет метод C, каждого из них в различном классе. Методы B и C оба перенесены с транзакциями. Оба использования PROPAGATION_REQUIRED, поэтому в то время как пружина создает две логических транзакции, существует одна физическая транзакция в дб.
Теперь, в методе C я бросаю RuntimeException. Это устанавливает внутреннюю логическую транзакцию как rollbackOnly и физическую транзакцию также. В методе B, я знаю о возможности UnexpectedRollbackException, таким образом, я не продолжаю фиксировать обычно. Я ловлю исключение из C, и я бросаю другой RuntimeException.
Я ожидаю, что внешний RuntimeException вызовет откат к внешней транзакции, Однако фактическое поведение - это:
Я нашел обходное решение для него, которое должно активно установить внешнюю транзакцию как откат только прежде, чем выдать исключение
public ModelAndView methodB(HttpServletRequest req, HttpServletResponse resp) {
try{
other.methodC();
} catch (RuntimeException e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw new RuntimeException ("outer exception");
}
return handleGetRequest(req, resp);
}
Однако это обходное решение сильно связывает код с API транзакций, и я хотел бы избежать этого. Какие-либо предложения?
p.s. обе транзакции предназначены для откатывания на исключениях на этапе выполнения. Я не определил rollbackFor исключения или чего-либо как этот
Вы можете попробовать установить failEarlyOnGlobalRollbackOnly
флаг в true
в вашем AbstractPlatformTransactionManager
наследнике (HibernateTransactionManager
, например). Вот его описание:
Устанавливает, следует ли досрочно завершать транзакцию в случае, если она глобально помечена как подлежащая откату.
По умолчанию "false", вызывая UnexpectedRollbackException только на внешней границе транзакции. Включите этот флаг, чтобы вызвать UnexpectedRollbackException уже при первом обнаружении глобального маркера "только откат", даже на внутренней границе транзакции. Обратите внимание, что начиная с версии Spring 2.0 поведение "отказ-раньше" для глобальных маркеров "только откат" было унифицировано: Все менеджеры транзакций по умолчанию будут вызывать UnexpectedRollbackException только на самой внешней границе транзакции. Это позволяет, например, продолжать модульные тесты даже после того, как операция завершилась неудачно и транзакция никогда не будет завершена. Все менеджеры транзакций будут выходить из строя раньше, только если этот флаг явно установлен в "true".