Почему изменение JPA-сущности внутри @Transactional сохраняется в БД без явного вызова save()?
- Зачем вызывать save() для managed-сущности?
Dirty checking: сущность, загруженная в транзакции, — managed; при flush (перед коммитом) Hibernate сравнивает её поля со снимком и сам отправляет UPDATE изменённых полей. save() не нужен.
- Работает только внутри транзакции и для managed-сущностей; detached — через merge/save
- Снимок каждой сущности — цена в памяти при больших выборках
- readOnly-транзакции отключают снимки и flush
А ещё Изменение «случайно» сохранится — не меняйте сущности, если не хотите записи
Подробно
Сущность, загруженная или сохранённая в рамках транзакции, становится managed и попадает в persistence context (кэш 1-го уровня) с снимком исходного состояния. Перед коммитом (или при flush) Hibernate сравнивает текущее состояние со снимком и для изменившихся полей сам генерирует UPDATE — отсюда «save() не нужен» для managed-сущностей. Важные следствия: (1) изменение detached-сущности (вне сессии) так не сохранится — нужен merge/save; (2) случайная мутация managed-сущности приведёт к незапланированному UPDATE; (3) для read-only сценариев dirty checking — лишняя работа, его отключают (@Transactional(readOnly=true)).
Что хотят услышать
- Persistence context, снимок, flush.
- Когда save всё-таки нужен.
- Цена в памяти и readOnly.
Частые ошибки
- Ждать сохранения от изменения detached-сущности без merge.
- Случайно менять managed-сущность и удивляться лишнему UPDATE.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Spring перехватывает все сеттеры сущности и пишет каждое изменение в базу немедленно
- ✗Изменения сохраняются только после явного вызова entityManager.refresh()
- ✓Dirty checking: на flush Hibernate сверяет managed-сущность со снимком
- ✗JPA пишет каждое изменение поля в базу отдельным запросом сразу после сеттера
Что спросят дальше
- Чем managed отличается от detached?
- Что даёт @Transactional(readOnly=true)?
Разбор темы
- Spring Data JPA: репозитории и Hibernate
Абстракция репозитория, derived queries и @Query, persistence context и dirty checking, lazy/N+1 и почему DTO, а не entity.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.