Last updated 19 September 2026. Default examples are mid-level Spring and Java 17–21. Junior and senior sit in labeled sections so the first screen is not a fresher dump.
Hibernate is the JPA implementation most Java interviews still mean when they say ORM. JPA is the API. Hibernate is the engine. If you cannot separate those two sentences, start at Junior. This hub covers mapping, sessions, flushing, and the queries that blow up in production. Hibernate II stays a sibling list; this URL is the head term.
Junior
An entity is a class mapped to a table. @Id is required. @GeneratedValue picks how the id is assigned. IDENTITY uses the database identity column and often disables JDBC batching. SEQUENCE uses a sequence and batches well. AUTO is a vendor-specific guess; name the strategy in an interview.
Session and EntityManager wrap a persistence context: a first-level cache of managed instances. persist makes a new instance managed. merge copies state onto a managed instance. find loads by id. A detached instance is not tracked; changing it does nothing until you merge. Transient means new and not associated. Removed means scheduled for delete.
Lazy versus eager: @ManyToOne is eager by JPA default, which surprises people. @OneToMany is lazy. LazyInitializationException means you touched a lazy association after the session closed. The junior fix is not OpenSessionInView by default; it is a query that fetches what the view needs.
JPQL is object query language. Native SQL is for vendor features. Criteria is type-safe and verbose. Named queries are compiled at startup. Pick one style per module and stop mixing four query languages in one repository.
Mid-level
Flush modes: AUTO flushes before queries that might be stale and before commit. MANUAL means you own it. Hibernate dirty-checks managed entities at flush. Changing a field on a managed entity schedules an UPDATE even if you never called save. That is the point of the persistence context, and it is how people write accidental updates.
N+1: one query for parents, then one per parent for children. Fix with join fetch, @EntityGraph, or a batch size. join fetch plus pagination is a separate trap: Hibernate may have to fetch the collection in memory to page. Say that out loud.
First-level cache is the persistence context. Second-level cache is shared across sessions, usually via JCache. Query cache needs a timestamp region and is easy to get wrong under writes. Do not enable query cache because a blog said so.
Transactions: a Session is not a transaction. Spring @Transactional opens a transaction and binds a Session. Read-only transactions skip dirty checking. Propagation mistakes cause LazyInitializationException or surprising commits. equals and hashCode on entities should not use a generated id before persist if the entity goes in a Set; use a business key or accept that the contract is messy.
Schema: ddl-auto=update is for laptops. Production uses Flyway or Liquibase. hbm2ddl create on Heroku is how you lose a catalog.
Senior
Senior Hibernate is flush order, batching, and bytecode enhancement. jdbc.batch_size plus a sequence generator and reordering inserts. StatelessSession skips the first-level cache for bulk work. Persistence context size is a memory leak if you stream a million rows in one session.
Locking: optimistic @Version is the default for user edits. Pessimistic locks (PAND, PWRITE) hit the database. Lost updates without a version column are a design bug. Isolation level is a database setting Spring can request; Hibernate will not invent repeatable read for you on PostgreSQL read committed.
Inheritance: SINGLE_TABLE, JOINED, TABLE_PER_CLASS. Discriminator columns, unused-null columns, and join costs. Embeddable types versus one-to-one. AttributeConverter for value types instead of wrapping a String in an entity.
Hibernate 6 query API and the removal of Criteria from the old org.hibernate.Criteria world. Jakarta persistence namespace. If the interview still shows Session.createCriteria, date the stack.
Probe yourself
Session.get versus load, or EntityManager.find versus getReference?
find/get hit the database (or cache) and may return null. getReference/load return a proxy and throw if you access it and the row is missing.
What causes LazyInitializationException?
Accessing a lazy association after the persistence context closed. Fetch in the query or keep a transaction open with a clear boundary.
Why can IDENTITY disable JDBC batch inserts?
The driver must insert to obtain the id before the next row, which breaks batched insert grouping.
Related questions on this topic are linked below. Read the full answer on the question URL; this hub does not repeat those answers.
Pitfalls interviewers still use
Open Session in View is the default in Boot and the reason lazy loads work in a Thymeleaf page. It also holds a connection for the whole view render and turns view-layer navigation into queries. Mid-level candidates should know it exists and that many teams turn it off. Senior candidates should say what they do instead: dedicated query DTOs.
hashCode on a generated id before persist: the id is null or -1, then changes, and your HashSet loses the entity. Use a business key or compare by identity in the persistence context only.
equals that compares every field including collections will recurse and stack overflow on bidirectional graphs. Interviewers love a Parent-Child equals that calls child.getParent().equals.
ddl-auto=create-drop on a shared dev database is how a team loses data on Friday. Name the migration tool you use. If you say none, expect a follow-up on how two developers add a column.
Fetching an entity to change one column and persist it again is a lost update without @Version. Two tabs, one remaining stock count, one oversell.
For the room: explain persist versus merge, when flush runs, and how you would kill an N+1 you have not seen yet (logging SQL, then entity graph). That is the Hibernate interview.
How to answer in the room
Open Hibernate with the persistence context, not with 'ORM maps objects to tables'. A persistence context is a first-level cache and an identity map. The same row loaded twice in one session is the same instance. Merge exists because a detached instance is not in that map.
N+1 is the mid-level test. You see it in SQL logs: one select for parents, then one per child. Fix with join fetch, an entity graph, or a dedicated DTO query. Do not 'fix' it by making every association EAGER. That moves the explosion to every other use of the entity.
LazyInitializationException means the session closed before a lazy association was touched. Open Session in View hides it in a web thread and holds a connection during view render. Many teams turn it off and use query DTOs. Say which you would pick and why.
equals and hashCode: never the generated id before persist if the instance enters a Set. Business key or identity within the session. Bidirectional equals that walk both sides will recurse. Interviewers still spring a Parent-Child pair on the whiteboard.
Flush points: commit, explicit flush, and query flush if needed for consistency. persist versus merge versus update (legacy). You should be able to say what happens if you merge a new instance that looks like an existing id.
Transactions and isolation: dirty read, non-repeatable, phantom. Hibernate does not invent isolation; the database does. @Version is optimistic locking for lost updates. Two tabs, one stock count, one oversell if you skip it.
Migrations: Flyway or Liquibase. ddl-auto=update is not a migration story for a shared database. Name the tool. If you have none, say how two developers add a column without deleting Friday's data.