Hibernate SQL Generation — Dirty Checking, ActionQueue, Flush Modes
Fast recall
Quick revision
Core answer
@DynamicUpdate is on). `FlushModeType`: AUTO (default — flushes before JPQL queries that might be affected and at commit), COMMIT (only at commit), ALWAYS (before every query), MANUAL (only on explicit em.flush()). The ActionQueue reorders queued SQL (INSERT -> UPDATE -> DELETE) to satisfy FK constraints; JDBC batching (hibernate.jdbc.batch_size) groups statements into batched round-trips. Two performance levers: `@DynamicUpdate` (smaller UPDATEs on wide tables) and `hibernate.order_inserts=true` (cross-table batching).Understanding of what actually happens inside a transaction before SQL hits the wire
Believing that calling `entity.setName()` immediately fires an UPDATE, or that Hibernate always flushes before every query
Discuss bytecode enhancement vs snapshot comparison, ActionQueue ordering, JDBC batching with `order_inserts`, and `@DynamicUpdate` cost-benefit
Interview-ready guide
Interview answer
Hibernate's SQL generation is automatic — you modify entities and Hibernate produces INSERT, UPDATE, DELETE statements. Knowing when that happens prevents stale reads and unexpected SQL volume.
Flush modes:
- AUTO (default) — flushes before JPQL queries that might be affected and at commit
- COMMIT — defers SQL to commit time; intermediate JPQL can see stale data
- ALWAYS — flushes before every query; expensive
- MANUAL — only on explicit
em.flush(); useful in read-only transactions
Dirty checking mechanics:
- At load time, Hibernate stores a snapshot of each entity's field values
- Before flush, compares current values to snapshot — fields that changed go into the UPDATE
- Default UPDATE includes all columns;
@DynamicUpdatelimits to changed only
Native query trap:
- Hibernate can't analyze native SQL to know if pending changes affect the result
- Always call
em.flush()before a native query that depends on in-memory changes
JDBC batching:
hibernate.jdbc.batch_size = 50groups statements into batched round-tripsorder_inserts: trueandorder_updates: trueare required for cross-table batchingbatch_versioned_data: trueis required for entities with@Version
Hibernate SQL Generation — Dirty Checking, ActionQueue, Flush Modes
Direct Answer
Hibernate's SQL generation is lazy and batch-oriented, controlled by three concepts: the persistence context (first-level cache), dirty checking via snapshot comparison, and flush modes. When you load an entity, Hibernate stores a snapshot of every field. Setter calls don't fire SQL — changes accumulate. At flush time, Hibernate compares each managed entity to its snapshot; if anything differs, it generates an UPDATE with all columns (unless @DynamicUpdate is on). FlushModeType: AUTO (default — flushes before JPQL queries that might be affected and at commit), COMMIT (only at commit), ALWAYS (before every query), MANUAL (only on explicit em.flush()). The ActionQueue reorders queued SQL (INSERT -> UPDATE -> DELETE) to satisfy FK constraints; JDBC batching (hibernate.jdbc.batch_size) groups statements into batched round-trips. Two performance levers: @DynamicUpdate (smaller UPDATEs on wide tables) and hibernate.order_inserts=true (cross-table batching).
Common Mistakes & Pitfalls
Believing that calling entity.setName() immediately fires an UPDATE, or that Hibernate always flushes before every query
Check your understanding
Answer these without looking back at the article.
- What happens to dirty checking if you hold thousands of entities in a single Session — and how do you mitigate it?
- How does bytecode enhancement differ from the default snapshot-based dirty checking?
- When would you explicitly set `FlushMode.COMMIT` and what are the risks?
- Why does `@DynamicUpdate` sometimes hurt performance instead of helping?
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.