Сначала ответь вслух
Скажи ответ вслух хотя бы пару минут, потом открой эталон и сравни. Эталон открыт всем и не требует входа.
Показать ответ
Эталонный ответ
REQUIRED (по умолчанию) работает в текущей транзакции, а если её нет — открывает. Все методы цепочки коммитятся или откатываются вместе.
REQUIRES_NEW приостанавливает внешнюю транзакцию и открывает новую физическую транзакцию на другом соединении. Запись в журнал аудита сохранится, даже если внешняя транзакция откатится.
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logAttempt(Attempt attempt) {
auditRepository.save(attempt); // переживёт откат внешней транзакции
}Цена: каждое такое вложение держит второе соединение из пула. Под нагрузкой пул может кончиться, и потоки встанут, ожидая соединение друг у друга.
Как у тебя получилось?
Уточняющие вопросы
Так обычно копают глубже. Раскрой строку, когда ответишь вслух.
Уточнение 1-го уровня: Откуда берётся UnexpectedRollbackException?
Ответ уровня Middle
Внутренний метод с REQUIRED бросил исключение и пометил общую транзакцию только для отката. Внешний метод исключение поймал и попытался закоммитить — Spring откатывает и сообщает об этом исключением.
Уточнение 2-го уровня: Чем NESTED отличается от REQUIRES_NEW?
Ответ уровня Senior
NESTED работает в той же физической транзакции через точку сохранения: откат вложенной части возвращает к точке, а откат внешней отменяет всё. Поддерживается для JDBC-транзакций.
Типичные ошибки
- Использовать REQUIRES_NEW «для надёжности» везде и исчерпать пул соединений.
- Ждать, что REQUIRES_NEW сработает при вызове из того же класса.
Первоисточники
Быстрые задания по теме
Для темы «Распространение транзакций» быстрых заданий пока нет
Можно проверить всю зону «Spring» тестом на 10 минут.
Проверить себя за 10 минут