У меня есть следующий странный сценарий с управлением транзакциями Spring:
У меня есть метод A, который вызывает метод B, который вызывает метод C, каждый из которых относится к своему классу.Методы B и C заключены в транзакции.Оба используют PROPAGATION_REQUIRED, поэтому пока Spring создает две логические транзакции, в БД есть одна физическая транзакция.
Теперь в методе CI выдается исключение RuntimeException.Это устанавливает внутреннюю логическую транзакцию как rollbackOnly, а также физическую транзакцию.В методе B я знаю о возможности UnexpectedRollbackException, поэтому я не продолжаю фиксировать в обычном режиме.Я ловлю исключение из C и выкидываю еще одно RuntimeException.
Я ожидаю, что внешнее RuntimeException вызовет откат к внешней транзакции, однако фактическое поведение таково:
- внешняя транзакция пытается зафиксировать или хотя бы проверить ее состояние, а затем выдает исключение UnexpectedRollbackException, поскольку физическая транзакция уже была помечена как rollbackOnly.
- Прежде чем вызвать это исключение, оно печатает в журналах другое исключение,заявив, что «исключение приложения переопределено исключением из коммита».Таким образом, вызывающий объект A получает исключение UnexpectedRollbackException, а не исключение, которое выбрасывает B.
Я нашел для него обходной путь, который заключается в активной установке внешней транзакции в качестве отката только перед созданием исключения
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, и я бы хотел этого избежать.Любые предложения?
ps обе транзакции предназначены для отката на исключения во время выполнения.Я не определил откат для исключения или что-то в этом роде