Що робить метод refresh()
Метод refresh() перезавантажує сутність з бази даних, замінюючи поточні значення в пам'яті актуальними даними з БД. Це корисно при роботі з тригерами, конкурентними оновленнями...
Огляд
Метод refresh() перезавантажує сутність з бази даних, замінюючи поточні значення в пам’яті актуальними даними з БД. Це корисно при роботі з тригерами, конкурентними оновленнями та коли потрібно гарантувати актуальність даних.
🟢 Junior Level
Що робить refresh()
refresh() — перезавантажує сутність з бази даних, замінюючи поточні значення в пам’яті.
User user = entityManager.find(User.class, 1L);
user.setName("Changed in memory"); // змінили в пам'яті
// Інша транзакція змінила БД
// Або тригер змінив дані
entityManager.refresh(user); // перезавантажити з БД
// Тепер user має актуальні значення з БД
// "Changed in memory" — перезаписано
Коли використовувати
- Після тригерів — база змінила поля через тригер
- При конкурентних оновленнях — інша транзакція оновила дані
- Для отримання актуальних даних — коли є сумніви в актуальності
refresh vs detach
refresh() — оновити дані з БД (сутність залишається managed)
detach() — від'єднати сутність (без оновлення з БД)
Приклад
@Transactional
public void updateUser(User user) {
entityManager.persist(user);
// Тригер в БД встановив created_at
entityManager.refresh(user);
// Тепер user.getCreatedAt() містить значення з БД
}
🟡 Middle Level
refresh з LockMode
// OPTIMISTIC — перевірка version
entityManager.refresh(user, LockModeType.OPTIMISTIC);
// PESSIMISTIC_READ — блокування на читання
entityManager.refresh(user, LockModeType.PESSIMISTIC_READ);
// PESSIMISTIC_WRITE — блокування на запис
entityManager.refresh(user, LockModeType.PESSIMISTIC_WRITE);
Типові помилки
// ❌ refresh без причини
User user = entityManager.find(User.class, 1L);
entityManager.refresh(user); // ❌ зайвий SELECT!
// ❌ refresh для detached
User detached = getDetachedUser();
entityManager.refresh(detached); // ❌ IllegalArgumentException
// ✅ refresh тільки для managed
User managed = entityManager.find(User.class, 1L);
entityManager.refresh(managed); // ✅
Коли refresh НЕ потрібен
// ❌ Не потрібен refresh після persist, якщо в БД немає тригерів
User user = new User();
entityManager.persist(user);
entityManager.refresh(user); // ❌ дані ті самі
// ❌ Не потрібен refresh після merge
User managed = entityManager.merge(detached);
entityManager.refresh(managed); // ❌ дані вже актуальні
// ✅ Потрібен після тригерів
entityManager.persist(user);
entityManager.flush();
entityManager.refresh(user); // ✅ тригер міг змінити дані
🔴 Senior Level
Внутрішня реалізація
refresh():
1. Перевірити що entity managed (не detached)
2. Виконати SELECT * FROM table WHERE id = ?
3. Оновити всі поля entity з результату
4. Оновити snapshot в persistence context
5. Оновити EntityEntry
refresh та генерація ID
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(insertable = false, updatable = false)
private LocalDateTime createdAt; // встановлено тригером
}
User user = new User();
entityManager.persist(user);
entityManager.flush();
entityManager.refresh(user); // отримати createdAt з БД
Best Practices
✅ refresh() після тригерів БД
✅ refresh() при конкурентних змінах
✅ З LockMode коли потрібне блокування
✅ flush() перед refresh() для синхронізації
❌ refresh() без причини (зайвий SELECT)
❌ refresh() для detached entities
❌ refresh() замість dirty checking
🎯 Шпаргалка для співбесіди
Обов’язково знати:
- refresh() перезавантажує сутність з БД, замінюючи поточні значення
- Використовується після тригерів, при конкурентних оновленнях, для актуальності даних
- Підтримує LockMode: OPTIMISTIC, PESSIMISTIC_READ, PESSIMISTIC_WRITE
- Працює тільки для managed сутностей, для detached — IllegalArgumentException
Пов’язані теми:
- [[8. Що таке стани transient, persistent, detached, removed]]
- [[14. У чому різниця між persist() і merge()]]
- [[17. Як реалізувати оптимістичне блокування в JPA]]
- [[18. Як реалізувати песимістичне блокування в JPA]]