Откатывать всю пачку или сохранять частично при ошибках сохранения данных в базе?
Что проверяют
Умеете ли вы вывести решение из требований, а не выбрать вариант наугад. Вопрос на самом деле про границу транзакции: одна ли это бизнес-операция или набор независимых записей. Дальше почти всегда идут детали Spring, потому что именно там кандидаты путаются.
Как отвечать
Начните со встречного уточнения: связаны ли элементы пачки общим инвариантом. Перевод между счетами атомарен, тут только полный откат. Импорт сотни тысяч строк из файла не атомарен: одна кривая строка не должна отменять всю ночную загрузку.
Для независимых элементов разумна обработка порциями: транзакция на пачку умеренного размера, битые элементы уходят в журнал ошибок с причиной, повтор загрузки идемпотентен по бизнес-ключу. Для атомарного случая одна транзакция, но с оглядкой на её длину: долгая транзакция держит блокировки и мешает очистке старых версий строк.
Технические детали, которых ждут:
@Transactionalпо умолчанию откатывается только на непроверяемых исключениях, для проверяемых нуженrollbackFor;- вызов транзакционного метода изнутри того же бина идёт мимо прокси, и транзакции не будет вовсе;
- пойманное внутри исключение не снимает пометку rollback-only, на коммите прилетит
UnexpectedRollbackException; - после исключения в JPA сессию нельзя использовать дальше, её состояние не определено;
REQUIRES_NEWдаёт отдельную транзакцию на элемент, но забирает ещё одно соединение из пула.
Где спотыкаются
Ловят исключение внутри транзакции и считают, что остальное сохранилось. На деле пачка помечена к откату, и данных, которые якобы записали, после коммита не существует.
Заворачивают миллион строк в одну транзакцию. Блокировки держатся часами, журнал растёт, а ошибка на последней строке отправляет работу на повтор с самого начала.
Сохраняют частично и не фиксируют, что именно не прошло. Никто не знает, каких записей не хватает, а повторный прогон без ключа идемпотентности создаёт дубли поверх уже загруженного.