У чому різниця між persist() і merge()
persist() та merge() — два ключові методи EntityManager для управління життєвим циклом сутностей. Розуміння різниці між ними критично важливе для правильного використання Hibern...
Огляд
persist() та merge() — два ключові методи EntityManager для управління життєвим циклом сутностей. Розуміння різниці між ними критично важливе для правильного використання Hibernate.
🟢 Junior Level
Основна відмінність
persist() — для нових сутностей (виконує INSERT).
merge() — для оновлення detached сутностей (виконує UPDATE або INSERT).
// persist — для нових сутностей
User newUser = new User();
newUser.setName("John");
entityManager.persist(newUser); // INSERT
// newUser тепер Persistent
// merge — для detached сутностей
User detached = getDetachedUser();
User managed = entityManager.merge(detached); // UPDATE
// managed — нова managed копія
// detached залишається detached!
Поведінка
| persist() | merge() | |
|---|---|---|
| Для | Transient | Detached |
| SQL | INSERT | UPDATE або INSERT |
| Повертає | void | Managed entity |
| Вихідний об’єкт | Стає managed | Залишається detached |
🟡 Middle Level
persist() детально
User user = new User();
entityManager.persist(user);
// Що відбувається:
// 1. Перевіряє що entity не managed
// 2. Генерує ID (якщо auto)
// 3. Додає в persistence context
// 4. Планує INSERT при flush
// 5. user стає Persistent
merge() детально
User detached = getDetachedUser();
User managed = entityManager.merge(detached);
// Що відбувається всередині:
// 1. Перевіряє чи є entity з таким ID в persistence context
// 2. Якщо немає — завантажує з БД (SELECT)
// 3. Копіює стан з detached в managed
// 4. Планує UPDATE при flush (якщо є зміни)
// 5. Повертає managed entity
// ВАЖЛИВО:
// detached залишається detached!
// Всі подальші операції — з managed!
Типові помилки
// ❌ merge() для нової сутності — зайвий SELECT
User newUser = new User();
entityManager.merge(newUser);
// ✅ persist() для нових
entityManager.persist(newUser); // Одразу INSERT
// ❌ persist() для detached сутності — EntityExistsException
User detached = getDetachedUser();
entityManager.persist(detached); // ❌
// ✅ merge() для detached
entityManager.merge(detached);
// ❌ Ігнорування return value merge()
entityManager.merge(detached); // результат втрачено!
detached.setName("Changed"); // НЕ збережеться!
// ✅ Використовуйте return value
User managed = entityManager.merge(detached);
managed.setName("Changed"); // збережеться
Generic save метод
public <T extends BaseEntity> T save(T entity) {
if (entity.getId() == null) {
entityManager.persist(entity);
return entity;
} else {
return entityManager.merge(entity);
}
}
🔴 Senior Level
Внутрішня реалізація
persist():
1. check if entity already managed → error if yes
2. schedule INSERT (не виконує одразу!)
3. add to persistence context
4. entity becomes managed
merge():
1. check if entity with same ID in persistence context
2. if not in DB: create new managed instance
3. copy state from detached to managed
4. schedule UPDATE if state changed
5. return managed entity
Продуктивність
persist():
- 0 SELECT запитів
- 1 INSERT при flush
merge():
- 1 SELECT (перевірка існування)
- 1 UPDATE або INSERT при flush
Для нових entities persist() швидший на 1 SELECT!
Best Practices
✅ persist() для нових сутностей
✅ merge() для detached сутностей
✅ Перевіряти ID перед вибором методу
✅ Використовувати return value merge()
✅ Generic save() з перевіркою ID
❌ merge() для нових (зайвий SELECT)
❌ persist() для detached (помилка)
❌ Ігнорування return value merge()
🎯 Шпаргалка для співбесіди
Обов’язково знати:
- persist() — для нових (Transient → Persistent), виконує INSERT
- merge() — для detached, повертає НОВИЙ managed об’єкт, виконує UPDATE/INSERT
- persist() швидший на 1 SELECT (не перевіряє існування)
- Оригінал після merge() залишається detached — всі операції з returned object
- Generic save(): перевірка ID == null → persist, інакше merge
Пов’язані теми:
- [[7. Опишіть життєвий цикл Entity в Hibernate]]
- [[8. Що таке стани transient, persistent, detached, removed]]
- [[12. Що таке dirty checking в Hibernate]]
- [[13. Як працює механізм flush в Hibernate]]
- [[15. Що робить метод refresh()]]