Получить доступ

Почему изменение JPA-сущности внутри @Transactional сохраняется в БД без явного вызова save()?

MiddleSpring Data JPA и HibernateHibernate / JPASpring Data
Ещё спрашивают так:
  • Зачем вызывать save() для managed-сущности?
Коротко

Dirty checking: сущность, загруженная в транзакции, — managed; при flush (перед коммитом) Hibernate сравнивает её поля со снимком и сам отправляет UPDATE изменённых полей. save() не нужен.

  • Работает только внутри транзакции и для managed-сущностей; detached — через merge/save
  • Снимок каждой сущности — цена в памяти при больших выборках
  • readOnly-транзакции отключают снимки и flush

А ещё Изменение «случайно» сохранится — не меняйте сущности, если не хотите записи

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Сущность, загруженная или сохранённая в рамках транзакции, становится 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.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓Это dirty checking: управляемая (managed) сущность находится в persistence context, и на flush/commit Hibernate сравнивает её с снимком и сам генерирует UPDATE для изменённых полей
  • ✗Spring перехватывает все сеттеры и пишет в БД немедленно
  • ✗Изменения сохраняются только если вызвать entityManager.refresh()
  • ✗JPA пишет каждое изменение поля отдельным запросом сразу

Что спросят дальше

  • Чем managed отличается от detached?
  • Что даёт @Transactional(readOnly=true)?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем