Logo

dev-resources.site

for different kinds of informations.

Persistence Context в Hibernate Zoo: путешествие объекта по жизненным состояниям

Published at
12/6/2024
Categories
java
hibernate
webdev
beginners
Author
easycat
Categories
4 categories in total
java
open
hibernate
open
webdev
open
beginners
open
Author
7 person written this
easycat
open
Persistence Context в Hibernate Zoo: путешествие объекта по жизненным состояниям

Добро пожаловать в Hibernate Zoo! Сегодня у нас увлекательное представление: встречайте Persistence Context! Этот веселый и усердный приятель — супергерой для ваших данных, сидящих в базе, и ловкач, который умеет управляться с хитрыми связями и объектами. Чтобы почувствовать себя настоящим исследователем, не забудьте надеть виртуальные очки Java, а код мы с вами закидаем прямо по ходу экскурсии.

Секреты за кулисами: что же такое Persistence Context?

Persistence Context — это, если уж говорить серьезно, некий контейнер для всех объектов, которые Hibernate отслеживает во время работы с базой данных. И как только вы начинаете транзакцию, Persistence Context тут как тут. Он наблюдает за каждым объектом, кэширует их, чтобы при повторных запросах не дергать базу данных понапрасну, и управляет состоянием всех сущностей.
Представьте его как упитанного енота с корзиной: он обходит все ваши объекты, с радостью добавляет их в корзинку, запоминает и хранит при себе, пока не закончится транзакция. А потом (бац!) он сохранит их в базе данных одним движением.

Жизненные стадии объектов в контексте персистенции Hibernate
В мире Hibernate объект может переходить из одного состояния в другое, и это критически важно для управления его жизненным циклом. Понимание этих стадий помогает эффективно управлять сохранением, обновлением и удалением данных. Итак, представьте, что ваш объект путешествует по четырём разным стадиям, как по уровням компьютерной игры.

Transient (Гость у ворот)

Когда объект только что создан и ещё не привязан ни к базе данных, ни к Hibernate-сессии, он находится в состоянии Transient (или "Переходное состояние"). Hibernate о нём ничего не знает, и, следовательно, он не будет сохранён в базе данных до тех пор, пока не попадёт под управление контекста персистенции.

Пример: Кот Бублик только появился

Cat cat = new Cat("Бублик", "серый");  // Transient
System.out.println("Имя кота: " + cat.getName());

Enter fullscreen mode Exit fullscreen mode

Persistent (Взяли под крылышко)

Теперь, когда вы решили, что ваш кот (или другой объект) заслуживает внимания и должен быть сохранён в базе, вы вызываете метод save() или persist(). После этого он становится persistent и Hibernate начинает за ним следить. Все изменения, которые вы будете вносить в этот объект, будут автоматически отслеживаться и сохранены в базе данных при закрытии транзакции.

Persistent cat
Пример: Бублик обрел дом в базе

Session session = sessionFactory.openSession();
session.beginTransaction();

Cat cat = new Cat("Бублик", "серый");
session.save(cat);  // Теперь кот стал persistent
cat.setColor("белый");  // Изменили цвет

session.getTransaction().commit();
session.close();

Enter fullscreen mode Exit fullscreen mode

Теперь кот Бублик persistent: Hibernate "запомнил" его и, когда вы закрываете транзакцию, изменения (например, смена цвета на белый) автоматически сохраняются в базе данных.

Detached (Бублик без надзора)

Когда сессия Hibernate закрывается (например, после вызова session.close()), объекты, которые были persistent, становятся detached. Это значит, что теперь они больше не отслеживаются Hibernate и никакие изменения, которые вы внесете в них, не будут автоматически сохранены.

Представьте, что кот Бублик убежал на улицу, и теперь Hibernate за ним больше не присматривает.

Пример: Бублик уходит, но он уже не в контексте

Session session = sessionFactory.openSession();
session.beginTransaction();

Cat cat = session.get(Cat.class, 1);  // Кот уже есть в базе и стал persistent
session.getTransaction().commit();
session.close();  // Теперь он detached

cat.setColor("черный");  // Изменение цвета больше не отслеживается Hibernate

Enter fullscreen mode Exit fullscreen mode

После закрытия сессии кот Бублик больше не находится под контролем Hibernate. Его статус detached, и если мы изменим его цвет на "черный", это не сохранится в базе данных.

Вернуть кота обратно в Hibernate
Чтобы снова привязать объект к контексту персистенции, можно использовать метод merge()

Session newSession = sessionFactory.openSession();
newSession.beginTransaction();

Cat mergedCat = (Cat) newSession.merge(cat);  // Бублик снова под контролем Hibernate
mergedCat.setColor("рыжий");  // Hibernate снова отслеживает изменения

newSession.getTransaction().commit();
newSession.close();
Enter fullscreen mode Exit fullscreen mode

После вызова merge() Hibernate снова начинает следить за Бубликом, и теперь все изменения будут сохранены.

Removed

Когда вы решаете, что объект больше не нужен в базе данных, вы можете пометить его для удаления с помощью session.delete(). Это переводит объект в состояние Removed. Объект ещё может существовать в памяти, но как только транзакция завершится, он исчезнет из базы данных. Итак, наш герой отправился вновь на поиски приключений.

Пример: Путь на свободу

Session session = sessionFactory.openSession();
session.beginTransaction();

Cat cat = session.get(Cat.class, 1);  // Бублик под контролем Hibernate
session.delete(cat);  // Пометили на удаление

session.getTransaction().commit();  // Бублик удалён из базы
session.close();

Enter fullscreen mode Exit fullscreen mode

Как только мы вызвали delete(), объект стал Removed. После завершения транзакции Бублик будет удалён из базы данных навсегда.

Схема переходов состояний в Hibernate

Чтобы наглядно представить переходы между состояниями, можно использовать следующую схему:

TransientPersistent: объект сохраняется в базе данных с помощью session.save() или session.persist().
PersistentDetached: сессия закрывается, и объект выходит из-под контроля Hibernate.
DetachedPersistent: объект снова привязывается к Hibernate с помощью session.merge() или session.update().
PersistentRemoved: объект помечается для удаления с помощью session.delete().
perscontext

Методы для Управления Жизненным Циклом Объектов в Hibernate
Hibernate предоставляет множество методов для управления состояниями объектов. От создания до удаления, каждый метод влияет на объект и его связь с базой данных через Persistence Context. Давайте разберемся в каждом методе, их особенностях, типичных ошибках и полезных примерах.

Приведем основные методы Hibernate для управления жизненным циклом

save()
Назначение:
Сохраняет объект в базу данных, переводя его из Transient в Persistent.

Ключевые особенности:

Генерирует SQL-запрос INSERT, добавляя объект в базу.
Возвращает идентификатор (id), сгенерированный для объекта.
Не требует, чтобы объект уже существовал в базе

Cat murzik = new Cat("Мурзик", "серый"); // Transient
session.save(murzik); // Теперь murzik — Persistent
Enter fullscreen mode Exit fullscreen mode

Типичная ошибка:
Попытка вызвать save() для объекта с уже установленным идентификатором может вызвать ошибки из-за конфликта id.

persist()
Назначение:
Также переводит объект в состояние Persistent.

Отличие от save():

persist() ничего не возвращает.
Используется только для объектов, которые не имеют идентификатора (новые).
Пример:

Cat barsik = new Cat("Барсик", "рыжий");
session.persist(barsik); // Добавлен в Persistence Context
Enter fullscreen mode Exit fullscreen mode

Типичная ошибка:
persist() нельзя использовать для объектов, находящихся в состоянии Detached.

update()
Назначение:
Привязывает объект в состоянии Detached к текущей сессии и переводит его в Persistent.

Пример:

session.close(); // Объект стал Detached
session = factory.openSession();
session.update(detachedCat); // Привязываем обратно

Enter fullscreen mode Exit fullscreen mode

merge()
Назначение:
Объединяет изменения в объекте в состоянии Detached с текущим состоянием в Persistence Context.

Пример:

Cat detachedCat = session.get(Cat.class, 1);
session.close(); // Detached
detachedCat.setColor("белый");

session = factory.openSession();
session.merge(detachedCat); // Объединяет изменения с базой
Enter fullscreen mode Exit fullscreen mode

Отличие от update():

merge() создаёт новый объект, если Detached-объект уже существует в Persistence Context.
Это делает merge() более безопасным.

delete()
Назначение:
Удаляет объект из базы данных и переводит его в состояние Removed.

Пример:

session.delete(murzik); // Удаляет объект из базы
Enter fullscreen mode Exit fullscreen mode

Особенность:
После удаления объект остаётся в памяти, но больше не привязан к Persistence Context.

flush()
Назначение:
Принудительно синхронизирует состояние Persistence Context с базой данных.

Пример:

session.save(cat);
session.flush(); // Все изменения записаны в базу

Enter fullscreen mode Exit fullscreen mode

Типичная ошибка:
Если между flush() и commit() произойдёт ошибка, база останется несинхронизированной.

saveOrUpdate()
Назначение:
Сохраняет новый объект или обновляет существующий.

Пример:

Cat cat = new Cat("Барсик", "рыжий");
cat.setId(1); // Если id существует, объект будет обновлён
session.saveOrUpdate(cat);

Enter fullscreen mode Exit fullscreen mode

Особенность:

Используйте этот метод, если не уверены, новый объект или уже существующий.
Но это может вызвать больше запросов, чем нужно.

clear()
Назначение:
Очищает Persistence Context, удаляя все объекты из него.

Пример:

session.clear(); // Все объекты становятся Detached
Enter fullscreen mode Exit fullscreen mode

Типичная ошибка:
После clear() нельзя обращаться к объектам, ожидая, что они останутся Persistent.

detach()
Назначение:
Превращает объект в состояние Detached, исключая его из Persistence Context.

Пример:

session.detach(cat); // Теперь cat — Detached
Enter fullscreen mode Exit fullscreen mode

close()
Назначение:
Закрывает сессию Hibernate, делая все объекты Detached.

Пример: session.close();

Сложности и Типичные Ошибки

  • Ошибка при использовании update(): Если объект с таким же идентификатором уже существует в Persistence Context, Hibernate выбросит исключение. Решение: Использовать merge(), если не уверены в состоянии объекта.

Потеря данных из-за flush():
Если вызвать flush() перед commit(), изменения могут записаться в базу, но не будут зафиксированы.
Решение:
Использовать commit() сразу после flush().

  • Дублирование при использовании save():
    Если вы вызываете save() для объекта с установленным id, это может привести к нарушению уникальности.
    Решение:
    Проверяйте, существует ли объект, прежде чем вызывать save().

  • Ленивая загрузка (LazyInitializationException):
    Ошибка возникает, если вы пытаетесь получить доступ к связанным объектам после закрытия сессии.
    Решение:
    Использовать fetch=FetchType.EAGER.
    Загружать данные заранее с помощью JOIN FETCH.

Путешествие объектов в Hibernate Zoo — это захватывающее приключение, где на каждом этапе Бублик и его друзья попадают в разные состояния и взаимодействуют с базой данных через Persistence Context. В начале они свободны, как птицы (или коты!), потом попадают под строгий надзор, выходят в свободное плавание и, в конце концов, могут покинуть этот зоопарк навсегда.

hibernate Article's
30 articles in total
Favicon
JOOQ Is Not a Replacement for Hibernate. They Solve Different Problems
Favicon
Persistence Context в Hibernate Zoo: путешествие объекта по жизненным состояниям
Favicon
Unidirectional associations for one-to-many
Favicon
Como eu reduzi em até 99% o tempo de resposta da minha API
Favicon
Hibernate Zoo: Жадный Гиппопотам и Ленивый Лемур (Lazy vs Eager)
Favicon
🐾 Hibernate Zoo: Путеводитель по языкам запросов в мире данных 🐾
Favicon
How To Fetch Data By Using DTO Projection In Spring Data JPA
Favicon
Ubuntu 22.04 Hibernate Using Swap File
Favicon
Зоопарк Hibernate: N+1 запросов или как накормить жадного бегемота
Favicon
Spring Data JPA Stream Query Methods
Favicon
Uma breve introdução ao Hibernate
Favicon
Ubuntu hibernate
Favicon
Eager vs Lazy Initialization of Spring Beans
Favicon
Understanding JPA Mappings in Spring Boot: One-to-One, One-to-Many, Many-to-One, and Many-to-Many Relationships
Favicon
Java Hibernate vs JPA: Rapid review for you
Favicon
Hibernate Connection Library with GUI Generation
Favicon
what is JPA? explain few configurations
Favicon
Demystifying Hibernate: A Beginner's Journey
Favicon
How to deal with N+1 problems with Hibernate
Favicon
Java Hibernate vs JPA: Quick Review
Favicon
Uppercase table names in Spring Boot
Favicon
Hiring Alert - Java Developer- Blockchain
Favicon
H2 database Setup Error Unable to load name org.hibernate.dialect.Oracle10gDialect
Favicon
Capitalisation of table name generated by Hibernate when using MySQL server
Favicon
Display SQL statement generated by Hibernate JPA in Spring Boot environment
Favicon
Advanced and dynamic searching with Spring Data JPA
Favicon
Defining JPA/Hibernate Entities in Kotlin
Favicon
Criteria Queries and JPA Metamodel with Spring Boot and Kotlin
Favicon
How to save Hibernate Entity changes to Database
Favicon
Hibernate Cheat Sheet

Featured ones: