← Назад к вопросам

Какой жизненный цикл сущности в JPA?

2.0 Middle🔥 211 комментариев
#ORM и Hibernate

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Жизненный цикл сущности в JPA

JPA (Java Persistence API) определяет чёткий жизненный цикл для сущностей (entities). Понимание этого цикла критично для правильной работы с ORM и избежания ошибок.

Четыре состояния сущности

1. New (Новая/Transient)

Сущность только что создана, но не сохранена в БД и не управляется контекстом сохраняемости (persistence context).

User user = new User();
user.setName("Ivan");
// Сущность в состоянии New

2. Managed (Управляемая/Persistent)

Сущность управляется контекстом сохраняемости. Все изменения отслеживаются и будут синхронизированы с БД.

entityManager.persist(user); // Переход в Managed
// или
User retrieved = entityManager.find(User.class, 1L); // Managed

3. Detached (Отсоединённая)

Сущность больше не управляется контекстом. Это может произойти при закрытии сессии или явном отсоединении.

entityManager.close(); // Все сущности становятся Detached
// или
entityManager.detach(user);

4. Removed (Удалённая)

Сущность помечена для удаления и будет удалена при flush/commit.

entityManager.remove(user); // Состояние Removed
entityManager.flush(); // Удаление из БД

Переходы между состояниями

New → persist() → Managed
Managed → close() → Detached
Managed → remove() → Removed
Removed → flush() → Удалено из БД
Detached → merge() → Managed

Lifecycle Callbacks

JPA предоставляет аннотации для реагирования на изменения состояния:

@Entity
public class User {
    @Id
    private Long id;
    private String name;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
    
    @PrePersist
    protected void onCreate() {
        createdAt = LocalDateTime.now();
        updatedAt = LocalDateTime.now();
    }
    
    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
    }
    
    @PostLoad
    protected void onLoad() {
        System.out.println("Сущность загружена: " + name);
    }
    
    @PreRemove
    protected void onRemove() {
        System.out.println("Сущность будет удалена: " + id);
    }
}

Доступные Lifecycle аннотации

  • @PrePersist — перед вставкой в БД
  • @PostPersist — после вставки в БД
  • @PreUpdate — перед обновлением в БД
  • @PostUpdate — после обновления в БД
  • @PreRemove — перед удалением из БД
  • @PostRemove — после удаления из БД
  • @PostLoad — после загрузки из БД

Практический пример

public class UserService {
    private EntityManager em;
    
    public void createUser(String name) {
        // 1. New state
        User user = new User();
        user.setName(name);
        
        // 2. Managed state
        em.persist(user);
        em.flush(); // Вставляется в БД, onCreate() вызывается
        
        // 3. Managed state (изменения отслеживаются)
        user.setName("Updated Name");
        em.flush(); // Обновляется в БД, onUpdate() вызывается
    }
    
    public void deleteUser(Long userId) {
        User user = em.find(User.class, userId); // Managed
        em.remove(user); // Removed
        em.flush(); // Удаляется из БД, onRemove() вызывается
    }
    
    public void updateDetached(User detachedUser) {
        // detachedUser был загружен в другой сессии
        User managed = em.merge(detachedUser); // Detached → Managed
        managed.setName("New Name");
        em.flush();
    }
}

Важные моменты

  1. Dirty Checking — контекст автоматически обнаруживает изменения в Managed сущностях
  2. Lazy Loading — связи загружаются при обращении (работает только для Managed)
  3. Detached изменения не сохраняются — нужно использовать merge()
  4. flush() vs commit() — flush записывает в БД, commit завершает транзакцию
  5. EntityManager.clear() — отсоединяет все сущности

Сравнение persist() и merge()

// persist() — для новых сущностей
User newUser = new User();
em.persist(newUser); // New → Managed

// merge() — для detached сущностей
User detachedUser = ...; // Loaded в другой сессии
User managed = em.merge(detachedUser); // Detached → Managed

Вывод: Понимание жизненного цикла JPA сущностей необходимо для эффективной работы с ORM. Ключевые моменты: состояния (New, Managed, Detached, Removed), переходы между ними, и использование lifecycle callbacks для выполнения важных операций.