Как работает save в Spring Data JPA
Вопрос
Что происходит при вызове repository.save()? Когда он лишний и какие с ним бывают сюрпризы?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
isNew: id null, @Version или Persistable
Новая: persist, существующая: merge
merge возвращает другой управляемый объект
Вручную заданный id: лишний SELECT
Внутри транзакции изменения сохраняются через dirty checking без save
SQL уходит при flush, а не в момент save
Что могут спросить следом
- Когда нужен saveAndFlush?
- Как Hibernate узнаёт, что сущность изменилась?
Разбор
SimpleJpaRepository.save сначала решает, новая ли сущность: по умолчанию по id, равному null, а если есть @Version или реализован Persistable, по ним. Для новой вызывается persist, для старой merge, который при необходимости загружает запись и возвращает управляемую копию, поэтому дальше работаю с результатом save. Сюрприз с вручную заданным UUID: сущность считается не новой, и каждая вставка начинается с лишнего SELECT. Второе: для сущности, загруженной в той же транзакции, save не нужен, Hibernate сам найдёт изменения при flush через dirty checking. Третье: save не обязательно сразу пишет SQL, запросы уходят при flush, обычно при коммите или перед запросом. Если нужно получить ошибку constraint прямо сейчас, использую saveAndFlush.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.