What Does the refresh() Method Do
The refresh() method reloads an entity from the database, replacing current in-memory values with actual data from the DB. This is useful when working with triggers, concurrent...
Overview
The refresh() method reloads an entity from the database, replacing current in-memory values with actual data from the DB. This is useful when working with triggers, concurrent updates, and when data freshness must be guaranteed.
Junior Level
What Does refresh() Do
refresh() - reloads an entity from the database, replacing current in-memory values.
User user = entityManager.find(User.class, 1L);
user.setName("Changed in memory"); // changed in memory
// Another transaction changed the DB
// Or a trigger changed the data
entityManager.refresh(user); // reload from DB
// Now user has actual values from DB
// "Changed in memory" - overwritten
When to Use
- After triggers - database changed fields via trigger
- During concurrent updates - another transaction updated data
- To get actual data - when there’s doubt about freshness
refresh vs detach
refresh() - update data from DB (entity remains managed)
detach() - detach entity (without DB update)
Example
@Transactional
public void updateUser(User user) {
entityManager.persist(user);
// Trigger in DB set created_at
entityManager.refresh(user);
// Now user.getCreatedAt() contains value from DB
}
Middle Level
Detailed Usage
// After trigger
User user = new User();
user.setName("John");
entityManager.persist(user);
// flush -> trigger in DB set created_at
entityManager.flush();
entityManager.refresh(user); // get created_at from DB
// During concurrent updates
User user = entityManager.find(User.class, 1L);
// Another transaction updated user
entityManager.refresh(user); // synchronize with DB
refresh with LockMode
// OPTIMISTIC - version check
entityManager.refresh(user, LockModeType.OPTIMISTIC);
// PESSIMISTIC_READ - read lock
entityManager.refresh(user, LockModeType.PESSIMISTIC_READ);
// PESSIMISTIC_WRITE - write lock
entityManager.refresh(user, LockModeType.PESSIMISTIC_WRITE);
// With timeout
Map<String, Object> properties = Map.of(
"jakarta.persistence.lock.timeout", 5000
);
entityManager.refresh(user, LockModeType.PESSIMISTIC_WRITE, properties);
Common Mistakes
// refresh without reason
User user = entityManager.find(User.class, 1L);
entityManager.refresh(user); // unnecessary SELECT!
// refresh for detached
User detached = getDetachedUser();
entityManager.refresh(detached); // IllegalArgumentException
// refresh only for managed
User managed = entityManager.find(User.class, 1L);
entityManager.refresh(managed); // correct
When refresh is NOT Needed
// Not needed after persist if there are no triggers/generated columns in DB. If trigger sets fields - refresh is needed (see Junior example).
User user = new User();
entityManager.persist(user);
entityManager.refresh(user); // data is the same
// Not needed after merge
User managed = entityManager.merge(detached);
entityManager.refresh(managed); // data is already actual
// Needed after triggers
entityManager.persist(user);
entityManager.flush();
entityManager.refresh(user); // trigger may have changed data
Senior Level
Internal Implementation
refresh():
1. Check that entity is managed (not detached)
2. Execute SELECT * FROM table WHERE id = ?
3. Update all entity fields from result
4. Update snapshot in persistence context
5. Update EntityEntry
If LockMode specified:
- Add LOCK clause to SELECT
- Check version for OPTIMISTIC
refresh and ID Generation
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(insertable = false, updatable = false)
private LocalDateTime createdAt; // set by trigger
}
User user = new User();
entityManager.persist(user);
entityManager.flush();
entityManager.refresh(user); // get createdAt from DB
refresh and Lazy Loading
User user = entityManager.find(User.class, 1L);
user.getOrders().size(); // load collection
// Another transaction changed the collection
entityManager.refresh(user); // reload EVERYTHING including collections
// Or only collections
entityManager.refresh(user, Map.of(
"org.hibernate.refreshMode", RefreshMode.FETCH
));
// (Available in Hibernate 6+)
Advanced Patterns
// Pattern: refresh after bulk update
@Modifying
@Query("UPDATE User u SET u.status = :status WHERE u.age > :age")
int bulkUpdate(@Param("status") String status, @Param("age") int age);
// After bulk update - refresh affected entities
User user = entityManager.find(User.class, userId);
entityManager.refresh(user); // get actual data
Best Practices
refresh() after DB triggers
refresh() during concurrent changes
With LockMode when locking needed
flush() before refresh for synchronization
refresh() without reason (unnecessary SELECT)
refresh() for detached entities
refresh() instead of dirty checking
refresh() after persist/merge without necessity
Interview Cheat Sheet
Must know:
- refresh() reloads an entity from DB, replacing current values
- Used after triggers, during concurrent updates, for data freshness
- Supports LockMode: OPTIMISTIC, PESSIMISTIC_READ, PESSIMISTIC_WRITE
- Works only for managed entities, for detached - IllegalArgumentException
- In Hibernate 6+ there’s RefreshMode.FETCH for loading only collections
Frequent follow-up questions:
- When is refresh() needed? After DB triggers, during concurrent changes, after bulk update
- refresh vs detach? refresh - updates data from DB (remains managed), detach - detaches (without update)
- Why is refresh after persist useless? Data hasn’t changed, unnecessary SELECT
- Can refresh have a timeout? Yes, via properties: jakarta.persistence.lock.timeout
Red flags (DO NOT say):
- “refresh() after every persist” - unnecessary SELECT, same data
- “refresh() for detached” - IllegalArgumentException
- “refresh() instead of dirty checking” - dirty checking is automatic, refresh is forced
- “I don’t understand when refresh is needed” - only triggers, concurrent changes, bulk update
Related topics:
- [[8. What Are the Transient, Persistent, Detached, Removed States]]
- [[14. What is the Difference Between persist() and merge()]]
- [[17. How to Implement Optimistic Locking in JPA]]
- [[18. How to Implement Pessimistic Locking in JPA]]