Думаю, нам нужно различать между "логическими" областями транзакций и "физические" транзакции здесь...
Что создает PROPAGATION_REQUIRED, является логическая область транзакций для каждого метод, к которому он применяется. каждый такая область логической транзакции может индивидуально решать только откаты статус, с внешней транзакцией объем логически независим от внутренний объем транзакции. из конечно, в случае стандартного PROPAGATION_REQUIRED поведение, они будут сопоставлены с одним и тем же физическим сделка. Таким образом маркер только для отката установить во внутренней области транзакции влияет на внешнюю транзакцию шанс на самом деле совершить. Однако, поскольку внешний объем транзакций не принимать решения о самом откате, отката (тихо запускается внутренний объем транзакции) неожиданным на этом уровне - почему UnexpectedRollbackException бросается.
PROPAGATION_REQUIRES_NEW, напротив, использует полностью независимую транзакция для каждого затронутого объем транзакции. В этом случае основные физические транзакции быть разными и, следовательно, может совершать или отката независимо, с внешним транзакция не зависит от внутренней статус отката транзакции.
PROPAGATION_NESTED снова отличается в том, что он использует один физический транзакция с несколькими точками сохранения что он может вернуться назад. Такие частичные откаты разрешают внутреннюю транзакцию для запуска отката для его с внешней транзакцией способность продолжать физическое транзакции, несмотря на некоторые операции отбросив назад. Это обычно отображается на точки сохранения JDBC, поэтому будет работать только с ресурсом JDBC транзакции (Spring 's DataSourceTransactionManager).
Чтобы завершить обсуждение: UnexpectedRollbackException также может быть брошенным без приложения когда-либо установив маркер только для отката сам. Вместо этого транзакция инфраструктура может решить, что единственным возможным результатом является отката, из-за ограничений в текущее состояние транзакции. Это особенно применительно к XA сделки.
Как я сказал выше, бросая исключение во внутренней транзакции области охвата, а затем поймать это исключение в внешний охват и перевод его в бесшумный вызов setRollbackOnly там должен работать ваш сценарий. вызов внешней транзакции будет никогда не см. исключение. Поскольку вы беспокоиться только о таких тихих откатах из-за особых требований навязанный вызывающим, я бы даже утверждают, что правильная архитектура решение заключается в использовании исключений внутри уровень обслуживания и перевод эти исключения в молчаливые откаты на уровне фасада сервиса (справа прежде чем вернуться к этому специальному вызывающий абонент).
Так как ваша проблема, возможно, не только об исключениях отката, но скорее о любых исключениях, брошенных с вашего уровня обслуживания, вы можете даже использовать стандартные исключения откат на всем протяжении сервисный уровень, а затем ловить и записывать такие исключения после совершения сделки уже завершено, в некоторых адаптация фасада переводит ваш уровень обслуживания исключения в UI-специфическую ошибку состояния.
Юрген