Что такое propagation в параметрах транзакции Spring
Что проверяют
Понимаете ли вы, что происходит, когда транзакционный метод вызывает другой транзакционный метод. Список выучить легко, поэтому следом спрашивают про ловушки: почему не сработал REQUIRES_NEW и откуда взялся UnexpectedRollbackException.
Как отвечать
Propagation это атрибут @Transactional(propagation = ...): что делать, если при входе в метод транзакция уже есть или её нет. Значения перечисления Propagation:
REQUIRED: по умолчанию. Присоединиться к текущей транзакции или открыть новую;REQUIRES_NEW: всегда новая транзакция, текущая приостанавливается. Нужна, чтобы запись пережила откат основной операции: аудит, журнал попыток;NESTED: внутри текущей через savepoint JDBC, откат возвращает к точке сохранения, коммит остаётся общим.DataSourceTransactionManagerэто поддерживает, а вJpaTransactionManagerвложенные транзакции по умолчанию выключены: savepoint откатит SQL, но не состояниеEntityManager;SUPPORTS: есть транзакция, работает в ней; нет, выполняется без неё;NOT_SUPPORTED: выполняется без транзакции, текущая приостанавливается;MANDATORY: транзакция обязана быть, иначеIllegalTransactionStateException;NEVER: транзакции быть не должно, иначе то же исключение.
Затем механика. @Transactional работает через прокси, и атрибуты применяются, только когда вызов проходит через прокси бина, то есть при вызове метода другого бина. Откат по умолчанию идёт на непроверяемых исключениях и Error, для проверяемых нужен rollbackFor.
Где спотыкаются
Вызывают this.saveAudit() с REQUIRES_NEW из того же класса. Вызов идёт мимо прокси, новая транзакция не открывается, и аудит откатывается вместе с основной операцией. Выход: вынести метод в отдельный бин или взять TransactionTemplate.
Ловят исключение внутреннего метода с REQUIRED и ждут, что внешний закоммитится. Внутренний уже пометил общую транзакцию как rollback-only, и на коммите вылетает UnexpectedRollbackException.
Не учитывают, что REQUIRES_NEW берёт второе соединение из пула. Под нагрузкой все соединения заняты внешними транзакциями, каждая ждёт ещё одно, и сервис встаёт при свободной базе.