Какие варианты работы с транзакциями существуют
Что проверяют
Знаете ли вы декларативный и программный подходы и понимаете ли ограничения аннотации.
Как отвечать
1. Декларативно через @Transactional. Основной способ в Spring. Аннотация ставится на метод или класс, а границы транзакции задаёт каркас.
Параметры, которые стоит знать: распространение (продолжить существующую или открыть новую), уровень изоляции, признак только для чтения, время ожидания, список исключений для отката.
Ограничения, вытекающие из реализации через прокси:
- самовызов не работает: вызов метода изнутри того же класса идёт мимо обёртки, и транзакция не открывается вовсе. Самая частая практическая ошибка;
- аннотация не действует на приватных и финальных методах;
- по умолчанию откат происходит только на непроверяемых исключениях. Проверяемое исключение транзакцию не откатит, пока его явно не перечислить.
2. Программно. Через шаблон транзакции или напрямую через менеджер транзакций. Смысл в точном контроле границ: транзакция охватывает ровно нужный участок внутри метода, а не весь метод целиком. Удобно, когда до и после нужен код, которому транзакция не нужна: обращение к внешнему сервису, подготовка данных, отправка уведомления.
3. Вручную на уровне драйвера: отключить автоматическую фиксацию и вызывать подтверждение или откат самому. Встречается в коде без каркаса и в пакетных скриптах.
4. Распределённые транзакции между несколькими ресурсами через двухфазное подтверждение. В микросервисах их избегают, потому что они блокируют участников и плохо переживают падение координатора. Вместо них применяют сагу с компенсациями.
Практические правила поверх всего: транзакция должна быть короткой, внутри неё не делают сетевых вызовов и не ждут пользователя. Отдельная осторожность с открытием новой вложенной транзакции: она требует второго соединения, и при большом количестве такие вызовы исчерпывают пул.
Где спотыкаются
Зовут транзакционный метод изнутри своего же класса.
Ловят исключение внутри и удивляются, что отката не было.
Держат транзакцию открытой на время обращения к внешнему сервису.
Не знают, что проверяемые исключения по умолчанию не откатывают транзакцию.