Питання 15 · Розділ 16

Що робить метод refresh()

Метод refresh() перезавантажує сутність з бази даних, замінюючи поточні значення в пам'яті актуальними даними з БД. Це корисно при роботі з тригерами, конкурентними оновленнями...

Мовні версії: English Russian Ukrainian

Огляд

Метод refresh() перезавантажує сутність з бази даних, замінюючи поточні значення в пам’яті актуальними даними з БД. Це корисно при роботі з тригерами, конкурентними оновленнями та коли потрібно гарантувати актуальність даних.


🟢 Junior Level

Що робить refresh()

refresh() — перезавантажує сутність з бази даних, замінюючи поточні значення в пам’яті.

User user = entityManager.find(User.class, 1L);
user.setName("Changed in memory");  // змінили в пам'яті

// Інша транзакція змінила БД
// Або тригер змінив дані

entityManager.refresh(user);  // перезавантажити з БД
// Тепер user має актуальні значення з БД
// "Changed in memory" — перезаписано

Коли використовувати

  1. Після тригерів — база змінила поля через тригер
  2. При конкурентних оновленнях — інша транзакція оновила дані
  3. Для отримання актуальних даних — коли є сумніви в актуальності

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]]