Careeroza
Flush Modes
When Does Hibernate Flush
Flushing = sending pending changes (SQL) to the database. It is not commit; a rollback still undoes flushed changes.
| Mode | Flushes when | Use |
|---|---|---|
AUTO (default) | before commit, and before a query whose result could be affected by pending changes | normal code |
COMMIT | only at commit (queries may see stale data) | long read-heavy transactions |
MANUAL (Hibernate) | only when you call flush() | read-only transactions (Spring sets it for readOnly = true) |
ALWAYS (Hibernate) | before every query | rarely needed |
AUTO vs COMMIT
Example
A pending stock change and then a "low stock" query. With AUTO the query sees the change; with COMMIT it does not:
import java.util.*;
public class Main {
enum FlushMode { AUTO, COMMIT }
static class Session {
final Map<Long, Integer> db = new TreeMap<>(Map.of(1L, 12, 2L, 3, 3L, 40));
final Map<Long, Integer> pending = new TreeMap<>();
final FlushMode mode;
Session(FlushMode mode) { this.mode = mode; }
void setStock(long id, int stock) { pending.put(id, stock); } // dirty entity
void flush() {
pending.forEach((id, s) -> System.out.println(" update products set stock=" + s + " where id=" + id));
db.putAll(pending); pending.clear();
}
List<Long> lowStock() {
if (mode == FlushMode.AUTO && !pending.isEmpty()) flush(); // products table is affected
List<Long> ids = new ArrayList<>();
db.forEach((id, s) -> { if (s < 5) ids.add(id); });
System.out.println(" select id from products where stock<5 -> " + ids);
return ids;
}
}
public static void main(String[] args) {
for (FlushMode m : FlushMode.values()) {
System.out.println(m + ":");
Session s = new Session(m);
s.setStock(1L, 2); // product 1 just sold 10 units
s.lowStock();
}
}
}Output
AUTO: update products set stock=2 where id=1 select id from products where stock<5 -> [1, 2] COMMIT: select id from products where stock<5 -> [2]
Changing It
// JPA, whole EntityManager or one query
em.setFlushMode(FlushModeType.COMMIT);
query.setFlushMode(FlushModeType.COMMIT);
// Hibernate-specific modes
Session session = em.unwrap(Session.class);
session.setHibernateFlushMode(FlushMode.MANUAL);Note: Native SQL queries: Hibernate cannot always tell which tables they touch, so in AUTO mode it flushes the whole session before them (Hibernate 6 native queries flush by default). Add addSynchronizedEntityClass(Product.class) on a NativeQuery to be precise.