Что такое жизненный цикл сущности в Hibernate?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Жизненный цикл сущности в Hibernate
Жизненный цикл сущности (Entity Lifecycle) в Hibernate — это последовательность состояний, через которые проходит объект от создания до удаления. Понимание этого цикла критично для эффективной работы с ORM и избежания ошибок.
Четыре состояния жизненного цикла
1. Transient (Новая, не управляемая)
Объект существует только в памяти приложения, Hibernate о нём ничего не знает.
User user = new User();
user.setName("Ivan");
user.setEmail("ivan@example.com");
// Объект в состоянии Transient
// Hibernate его не отслеживает
// В БД записи нет
Характеристики Transient:
- Нет ID/первичного ключа
- Не отслеживается Session
- Нет соответствия в БД
- При GC объект будет удален
2. Persistent (Управляемая/Персистентная)
Объект управляется Hibernate Session и имеет соответствие в БД.
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = new User();
user.setName("Ivan");
user.setEmail("ivan@example.com");
session.persist(user); // Переход в Persistent
// или
session.save(user);
tx.commit();
// Объект теперь Persistent
// Имеет ID
// Отслеживается Session
// Соответствует записи в БД
Характеристики Persistent:
- Управляется Session
- Имеет ID/первичный ключ
- Любые изменения отслеживаются
- При commit изменения сохранятся в БД
- Lazy loading работает
3. Detached (Отсоединённая)
Объект был Persistent, но Session был закрыт или объект был явно отсоединён.
User user = session.get(User.class, 1L); // Persistent
session.close(); // Объект становится Detached
// Теперь user в состоянии Detached
// Session о нём не знает
// Изменения не будут отслеживаться
user.setName("New Name"); // Изменение НЕ будет сохранено
Отсоединение может быть явным:
Session session = sessionFactory.openSession();
User user = session.get(User.class, 1L);
session.detach(user); // Явное отсоединение
session.evict(user); // Альтернатива
session.clear(); // Отсоединить все объекты
Характеристики Detached:
- Имеет ID (был когда-то Persistent)
- НЕ управляется Session
- Изменения НЕ отслеживаются автоматически
- При присоединении (attach) может вернуться в Persistent
4. Removed (Удалённая)
Объект отмечен для удаления и будет удален при commit.
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = session.get(User.class, 1L); // Persistent
session.remove(user); // Переход в Removed
// или
session.delete(user);
tx.commit(); // SQL DELETE выполнится
// После commit объект становится Detached
Характеристики Removed:
- Отмечена для удаления
- Всё ещё управляется Session (временно)
- При commit будет выполнен DELETE
Диаграмма переходов между состояниями
Transient
|
|-- save()/persist() --> Persistent <-- merge()/update()
|
|-- close()/detach() --> Detached
|
|-- delete()/remove() --> Removed
|
|-- commit() --> Detached
Практические примеры переходов
Пример 1: Полный цикл
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
// 1. Transient
User user = new User();
user.setName("Alex");
// 2. Persistent
session.persist(user);
system.out.println("ID = " + user.getId()); // ID сгенерирован
// Изменение отслеживается
user.setName("Alexander");
tx.commit(); // UPDATE будет выполнен
session.close();
// 3. Detached
user.setName("Alex"); // Изменение НЕ сохранится
Пример 2: Повторное присоединение (Reattach)
Session session1 = sessionFactory.openSession();
User user = session1.get(User.class, 1L); // Persistent
session1.close(); // Detached
// Позже, в другой Session
Session session2 = sessionFactory.openSession();
Transaction tx = session2.beginTransaction();
user.setName("New Name");
session2.merge(user); // Или update(user)
// Объект снова Persistent в session2
tx.commit();
Пример 3: Cascade операции
@Entity
public class Post {
@OneToMany(cascade = CascadeType.ALL)
private List<Comment> comments;
}
// Удаление Post удалит и все Comment (Cascade)
Post post = session.get(Post.class, 1L); // Persistent
session.delete(post); // Removed
// Все comments также перейдут в Removed
Важные методы Session
| Метод | Действие | Результат |
|---|---|---|
| persist() | Transient → Persistent | INSERT |
| save() | Transient → Persistent | INSERT |
| update() | Detached → Persistent | UPDATE |
| merge() | Detached → Persistent | UPDATE (создаёт новый объект) |
| delete() | Persistent → Removed | DELETE |
| remove() | Persistent → Removed | DELETE |
| get() | Fetch | Persistent или null |
| load() | Lazy load | Persistent (proxy) |
| detach() | Persistent → Detached | Отсоединение |
| clear() | Persistent → Detached | Отсоединить все |
Критические ошибки
Ошибка 1: Использование Detached объекта без merge
Session session1 = sessionFactory.openSession();
User user = session1.get(User.class, 1L);
session1.close();
Session session2 = sessionFactory.openSession();
session2.update(user); // Ошибка! user Detached
// Нужно:
session2.merge(user);
Ошибка 2: Забыли commit
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = new User();
session.persist(user);
// tx.commit() забыли!
session.close(); // Изменения потеряны
Ошибка 3: Использование closed Session
Session session = sessionFactory.openSession();
User user = session.get(User.class, 1L); // Persistent
session.close();
user.getName(); // OK
user.getComments().size(); // LazyInitializationException!
// Collections инициализируются с Session
Решение:
// Инициализировать до close
Hibernate.initialize(user.getComments());
session.close();
user.getComments().size(); // OK
Граница транзакции и сессии
Open Session In View (OSIV) — паттерн для web-приложений:
// Spring Data выглядит как это работает внутри
public List<User> getAllUsers() {
// Session открыта
return userRepository.findAll();
// Session закрывается (Detached)
}
// В контроллере
List<User> users = getAllUsers(); // Detached
users.get(0).getComments().size(); // LazyInitializationException!
Заключение
Жизненный цикл сущности — это фундамент Hibernate. Ключевые моменты:
- Transient — новый объект, Session не знает
- Persistent — управляется Session, изменения отслеживаются
- Detached — был Persistent, Session закрыта
- Removed — отмечен для удаления
Понимание переходов помогает избежать LazyInitializationException, Lost Updates и других проблем с ORM.