skip to content

Hibernate

4 roadmaps253 questionsupdated

The JVM's dominant JPA implementation: how objects map to tables and how the engine loads, tracks, flushes, caches, and locks them. Interviewers treat Hibernate depth as the acid test of real backend experience, because its defaults — lazy loading, dirty checking, caching — cause the production incidents every senior candidate is asked to explain.

on this pageshow

guide

overview

~1 min

Hibernate is the most widely used implementation of Jakarta Persistence (JPA) on the JVM: it maps classes to tables, then loads, tracks, flushes, caches and locks those objects for you. Interviewers lean on it because its conveniences are also its incident reports. Lazy loading, automatic change detection and caching all behave well in a demo and badly under load when nobody knows what SQL they produce. A good Hibernate answer predicts the statements a piece of code will run, and when, before explaining any annotation. The hub follows that question. [Entity mapping and annotations](/topics/be-hibernate-entity-mapping) decides how a class becomes rows: identifiers, columns, embeddables, enums and inheritance. [Associations and fetching](/topics/be-hibernate-associations-fetching) decides how related rows arrive, and is where N+1 selects and `LazyInitializationException` live. The [persistence context and session](/topics/be-hibernate-persistence-context) is the engine in the middle: entity states, the first-level cache, dirty checking and flushing. [HQL, JPQL and the Criteria API](/topics/be-hibernate-hql-criteria) covers the query tools and which of them bypass that engine. [Caching](/topics/be-hibernate-caching) adds the shared second-level and query caches, [transactions and locking](/topics/be-hibernate-transactions-locking) handles concurrent writers, and [performance and tuning](/topics/be-hibernate-performance) closes the loop with batching, read-only reads and the statistics that show what actually ran. Junior rounds check the model: entity states, default fetch types, what a flush is. Senior and principal rounds are scenario questions — a slow screen, a lost update, a stale cache — where you are expected to name the evidence you would collect first. Learn mapping and the persistence context before anything else; fetching, queries and locking all describe what that context does with the mappings.

primer

### The persistence context is the model Every managed entity lives in a **persistence context** — a Hibernate `Session`, which is also a JPA `EntityManager`. It holds at most one object per database row, remembers what each object looked like when it was loaded, and decides when to write. Almost every Hibernate question, from "why did this UPDATE run" to "why is this value stale", is a question about what the context contains and when it talks to the database. ### Writes are deferred and inferred You rarely tell Hibernate to update anything. Changes to managed objects are detected by comparing them with their loaded state, queued, and sent at **flush** — usually just before commit, sometimes before a query that needs them. That makes writes cheap to express and hard to see, and it is why the ordering of statements, and the moment they fail, surprises people who think in terms of explicit saves. ### Loading is a fetch plan, chosen per use case Mappings say how entities relate; they should not say how much to load. Associations left lazy are loaded on first access through proxies or wrapped collections, which is harmless once and ruinous inside a loop. The durable habit is to keep mappings lazy and state the graph each use case needs in the query that loads it. Candidates who put that choice in the mapping end up defending either N+1 selects or oversized graphs. ### Mapping choices outlive the code Identifier generation, enum storage, inheritance layout and the owning side of an association are written into the schema. They decide whether inserts can be batched, whether a column survives a refactor, and how many joins a polymorphic query costs. Interviewers ask about them because they are expensive to change once data exists. ### Not every query goes through the context Entity queries return managed objects that the context tracks; DTO projections, native SQL, bulk `UPDATE`/`DELETE` and stateless sessions skip part or all of that bookkeeping. Knowing which tool bypasses which layer — the identity map, dirty checking, the second-level cache — is what lets you pick the cheap one without corrupting the state you still hold. ### Concurrency belongs to the database, checked by the ORM Isolation is the database's job. Hibernate's identity map adds repeatable reads for entities a session already holds, and beyond that it adds detection: a version column turns a silent lost update into a failed write, and explicit lock modes turn into locking reads. A strong answer names which of those the scenario needs and what the application does when the check fails.

Persistence context
The set of managed entity instances tied to one Session or EntityManager, holding one instance per row and tracking their changes until it is closed or cleared.
Session
Hibernate's native unit-of-work API. It implements JPA's EntityManager and adds Hibernate-only operations, reached from standard code by unwrapping.
SessionFactory
The heavyweight, thread-safe object built once from the mappings and configuration. It creates sessions and owns shared resources such as the second-level cache.
Entity state
Where an object stands relative to a persistence context: transient, managed, detached or removed. The state decides whether its changes will be written.
Flush
The moment Hibernate turns queued in-memory changes into SQL statements inside the open transaction. It is not a commit; a flushed change can still roll back.
Dirty checking
Detecting changed managed entities by comparing them with the state captured at load time, so an UPDATE is generated without any explicit save call.
First-level cache
Another name for the persistence context's identity map. It is always on, private to one session, and repeats a lookup by id without a new SELECT.
Second-level cache
An optional cache owned by the SessionFactory and shared by all sessions. It stores entity state rather than live objects and needs an external provider.
Proxy
A runtime-generated subclass standing in for a lazily loaded entity. It knows the identifier and loads the real row on first use, if its session is still open.
Owning side
The side of an association whose table holds the foreign key. Only its changes are written; the inverse side is marked with mappedBy.
Fetch plan
What a particular load brings back with the root entity: associations fetched eagerly, lazily, by join, in batches or through an entity graph.
N+1 selects
One query for a list of entities followed by one more query per entity when a lazy association is touched, usually inside a loop.
Entity graph
A JPA-standard declaration of which associations to load with an entity, applied per query instead of being fixed in the mapping.
DTO projection
A query that returns plain data objects built from selected columns instead of managed entities, so nothing is tracked or dirty-checked.
@Version
The mapping for an optimistic-locking column. Hibernate checks and increments it on every update, so a concurrent modification makes the write fail.

A Hibernate application starts by building one **SessionFactory** from the mappings; that is where mistakes in entity metadata surface and where the shared second-level cache lives. Each unit of work then opens a **session**, usually bound to one database transaction by the surrounding framework. Inside it, queries and lookups by id fill the persistence context; lookups check the context first, then the second-level cache if one is configured, then the database. Lazy associations sit in the context as proxies or uninitialized collections and load on first touch. At flush, dirty checking produces the SQL, ordered and optionally batched, with version checks folded into the `WHERE` clause. Commit ends the transaction; closing the session detaches everything it held, and a proxy touched after that point fails. The sections map onto that path: - **Mapping** fixes the shape of every statement: which columns, which joins, whether an id is known before the insert. - **Fetching** and **queries** decide what enters the context and how many round trips it takes. - **The persistence context** decides what leaves it, and when. - **Caching** sits between the context and the database for reads; **locking** guards the writes on the way out. - **Performance** work is almost always one of these layers doing more than the use case needed. Several ideas meet in a few ordinary lines: ```java @Transactional public void ship(long orderId) { Order order = em.createQuery( "select o from Order o join fetch o.lines where o.id = :id", Order.class) .setParameter("id", orderId) .getSingleResult(); // fetch plan chosen here, not in the mapping order.markShipped(); // no save call: the context tracks the change } // commit -> flush -> version-checked UPDATE ``` Assuming `Order` carries a `@Version` column, nothing in the method writes SQL, yet it decides one join, one tracked instance and one conditional update. Moving the fetch out of the query, or reading `order.getLines()` after the transaction has closed, changes the statement count or the outcome without changing a line of business logic.

  1. Entity Mapping & Annotations →

    How classes, identifiers and columns become tables; every later section assumes you can read a mapping and predict its schema.

  2. Persistence Context & Session →

    Entity states, flushing and dirty checking: the engine that explains when Hibernate reads and writes.

  3. Associations & Fetching →

    Relationships, lazy loading and fetch plans, where N+1 selects and lazy-loading failures come from.

  4. HQL, JPQL & Criteria API →

    The query tools, and which of them return managed entities versus plain data or bypass the context.

  5. Transactions & Locking →

    Optimistic versions and row locks, needed for every lost-update scenario an interviewer poses.

  6. Performance & Tuning →

    Batching, read-only reads and statistics; makes sense once loading, flushing and queries are clear.

  • Marking associations EAGER to avoid lazy-loading errors: the cost moves to every query that loads the entity, and it cannot be switched off per query.

  • Assuming persist or merge writes immediately: most statements wait for the flush, so a constraint violation can surface later, at commit or before an unrelated query.

  • Keeping the argument of merge and editing it afterwards: merge returns a different, managed instance, and only that one is tracked.

  • Treating Open Session in View as a fix for LazyInitializationException; it hides missing fetch plans and can hold a connection for the whole request. See Open Session in View Debate.

  • Basing equals/hashCode on a generated id, so an entity's hash changes when it is persisted while it sits in a HashSet.

  • Choosing IDENTITY generation for a write-heavy table without knowing it prevents Hibernate from batching inserts.

  • Running a bulk JPQL UPDATE and then trusting entities already loaded in the same session; they keep their old values until refreshed or cleared.

  • Relying on READ COMMITTED to prevent lost updates; without a version column or a locking read, the last writer silently wins.

  • Combining a collection fetch join with pagination and not noticing Hibernate paginates in memory — see Pagination & the Fetch-Join Trap.

This guide assumes Hibernate ORM 6.x, the line Spring Boot 3 ships, which implements Jakarta Persistence 3.x. A few changes along the way still come up because many production codebases, and many answers found online, predate them: - **5.2** made `Session` extend `EntityManager`, so native and standard APIs live on one object and unwrapping replaced most casting. - **6.0** moved from the `javax.persistence` to the `jakarta.persistence` package, rebuilt HQL and Criteria on a new query model, and changed implicit sequence naming to one sequence per entity instead of one shared default. It also stopped returning duplicate roots from a collection fetch join, a common reason older code added `DISTINCT`. - **7.x** is the newest line and implements Jakarta Persistence 3.2; it tightens and removes APIs that 6.x had deprecated. When an answer depends on version — the default identifier strategy, `DISTINCT` with fetch joins, the package names in a stack trace — say which one you are describing. The old Hibernate-specific Criteria API was removed in 6.0 and XML `hbm.xml` mappings are deprecated; interviewers who maintain older systems still ask about both, and naming the era is part of the answer.

Hibernate is rarely used alone. In Spring applications it usually sits under **Spring Data JPA**, which generates repositories and derives queries but delegates every load, flush and lock to Hibernate — so repository questions quickly become Hibernate questions. A connection pool such as HikariCP supplies its connections, and schema changes belong to a migration tool such as Flyway or Liquibase rather than Hibernate's own schema generation, which is a development convenience. Sibling projects extend it: Hibernate Validator for bean validation, Envers for audit history, Hibernate Search for full-text indexing. It competes on two axes. Among JPA implementations, EclipseLink is the main alternative; code written to the standard API moves between them, while Hibernate-specific annotations and HQL features do not. Against the ORM approach itself stand SQL-first tools — jOOQ, MyBatis, plain JDBC templates — which give up the identity map, dirty checking and lazy loading in exchange for SQL you write and read directly. The defensible choice names the workload: rich domain models with many writes favour an ORM; reporting, bulk work and complex SQL often favour a SQL-first layer, and many systems use both. [ORM & Data Access](/topics/be-orm) places these approaches side by side.

explore

report an issue with this guide →

questions

253 · 7 sections

What does the JPA specification require of a Java class before a provider such as Hibernate will accept it as a persistent entity, and what happens at runtime when one of those requirements is missing?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Mark the class @Entity, give it a no-arg constructor (public or protected), and declare an identifier with @Id. The class and its persistent members must not be final, otherwise Hibernate cannot instantiate it or build a lazy proxy.

open as a page

What does the JPA @Column annotation control on a simple entity attribute, and what happens to an attribute that carries no @Column at all?

level: juniorimportance: must knowfreq 58%
basics
~20 s

@Column names the column and describes its shape — length, precision/scale, nullable, unique, columnDefinition — and controls whether it appears in INSERT/UPDATE via insertable/updatable. Omit it and the attribute still maps, using a default name and defaults such as length 255.

open as a page

In JPA/Hibernate, what does annotating a class @Embeddable and referencing it with @Embedded from another class actually do, and how does such a value type differ from a class annotated @Entity?

level: juniorimportance: must knowfreq 68%
basics
~20 s

@Embeddable marks a value type with no identity. Its fields become extra columns in the owner's table: no separate table, no primary key, no lifecycle of its own. An @Entity has an identifier, its own row, and is tracked individually by the persistence context.

open as a page

How does JPA's @Enumerated annotation store a Java enum in the database, what is its default, and what is the practical difference between EnumType.ORDINAL and EnumType.STRING?

level: juniorimportance: must knowfreq 72%
basics
~20 s

By default (ORDINAL) JPA stores the enum constant's declaration index as a number, so reordering or inserting constants silently remaps existing rows. EnumType.STRING stores the constant's name, which is stable under reordering and readable, but breaks if you rename a constant.

open as a page

Do JPA/Hibernate entity classes need custom equals() and hashCode(), or is the reference comparison inherited from java.lang.Object good enough? When does the choice actually start to matter?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Object.equals compares references. That is correct only while every instance comes from one open persistence context, which guarantees one object per row. As soon as entities are detached, re-loaded in another session, merged, or compared across sessions, two objects represent the same row and reference equality says false — so you override equals/hashCode using a stable identifier.

open as a page

JPA offers four association mappings — @ManyToOne, @OneToMany, @OneToOne and @ManyToMany. Explain what each expresses, and how you would choose between them for a model of orders, customers and tags.

level: juniorimportance: must knowfreq 76%
basics
~20 s

They declare cardinality from the annotated field outward. @ManyToOne: many rows reference one (Order to Customer) and holds the foreign key. @OneToMany: the inverse collection (Customer to Orders). @OneToOne: at most one each way. @ManyToMany: many both ways, via a link table.

open as a page

In JPA, if you call EntityManager.persist() on a parent entity whose collection holds brand-new child entities, what happens to those children by default, and what does configuring cascade on that association change?

level: juniorimportance: must knowfreq 62%
basics
~20 s

By default persist applies only to the instance you pass. The new children stay transient, and at flush Hibernate typically fails with "object references an unsaved transient instance". Declaring cascade = PERSIST (or ALL) makes the provider run persist on each child too.

open as a page

In JPQL, what does the JOIN FETCH clause do, and how does it differ from writing a plain JOIN in the same query?

level: juniorimportance: must knowfreq 78%
basics
~20 s

JOIN FETCH tells the ORM to load the joined association's rows into the returned entities in the same SQL statement. A plain JOIN only lets you filter or navigate in the query; the association still loads later on access.

open as a page

In JPA, what does the @JoinColumn annotation declare, and which side of an association must carry it?

level: juniorimportance: must knowfreq 75%
basics
~20 s

@JoinColumn names the foreign-key column that stores the association. It goes on the owning side — the side whose table holds the FK, which for @ManyToOne is always the many side. The inverse side uses mappedBy instead.

open as a page

In JPA, what is the default fetch type for each of the four association annotations — @ManyToOne, @OneToOne, @OneToMany and @ManyToMany — and why does the default differ between them?

level: juniorimportance: must knowfreq 82%
basics
~20 s

To-one associations (@ManyToOne, @OneToOne) default to EAGER. To-many associations (@OneToMany, @ManyToMany) default to LAZY. The spec assumes fetching one extra row is cheap and fetching a whole collection is not. Most teams override the to-one defaults to LAZY.

open as a page

Which JPA entity lifecycle callback annotations exist, and at what point in an entity's lifecycle does each of them fire?

level: juniorimportance: must knowfreq 55%
basics
~20 s

Seven: @PrePersist and @PostPersist around the INSERT, @PreUpdate and @PostUpdate around the UPDATE, @PreRemove and @PostRemove around the DELETE, and @PostLoad after an entity is loaded from the database. Methods return void and take no arguments when declared on the entity.

open as a page

Inside a transaction you load an entity with EntityManager.find, call a setter on it, and never call persist, merge, or any save method — yet an UPDATE reaches the database when the transaction commits. Explain the mechanism that makes that happen.

level: juniorimportance: must knowfreq 76%
basics
~20 s

A loaded entity is managed by the persistence context, which kept a snapshot of the values it was loaded with. At flush (commit, by default) Hibernate compares the object with that snapshot, sees the changed field, and generates the UPDATE automatically. This is dirty checking; no save call is involved.

open as a page

In JPA/Hibernate, an entity instance is always in one of four lifecycle states with respect to a persistence context. Name those states and describe how an object moves from one to another.

level: juniorimportance: must knowfreq 80%
basics
~20 s

Transient (new, unknown to the context), managed (tracked by an open EntityManager, changes written automatically), detached (was managed, context ended), removed (scheduled for DELETE). persist, find/query, detach/clear/close, merge and remove move an object between them.

open as a page

Inside a single Hibernate Session you load the same database row twice by primary key. What do you get back the second time, and what mechanism guarantees that result?

level: juniorimportance: must knowfreq 70%
basics
~20 s

You get the very same Java instance — the two references are ==, and the second load usually issues no SQL. The persistence context is an identity map keyed by entity type plus primary key, holding at most one instance per row for the life of the session.

open as a page

In JPA/Hibernate, what does it mean to "flush" the persistence context, and how is flushing different from committing the transaction?

level: juniorimportance: must knowfreq 66%
basics
~20 s

Flushing sends the INSERT/UPDATE/DELETE statements the persistence context has queued to the database inside the open transaction. Committing ends the transaction and makes them permanent. Commit always flushes first, but a flush alone can still be rolled back.

open as a page

Walk through how you build and execute a simple query with the JPA Criteria API — what roles do CriteriaBuilder, CriteriaQuery, Root and TypedQuery each play?

level: juniorimportance: must knowfreq 55%
basics
~20 s

EntityManager.getCriteriaBuilder() gives a CriteriaBuilder, the factory for everything. It creates a CriteriaQuery<T> that fixes the result type. Root<E> is the FROM entity and the handle for attribute paths. You set select/where/orderBy, then em.createQuery(cq) returns an executable TypedQuery<T>.

open as a page

How do you make a JPQL query return instances of a plain DTO class instead of mapped entities using a constructor expression, and what must the DTO class provide for it to work?

level: juniorimportance: must knowfreq 55%
basics
~20 s

Write select new com.example.OrderView(o.id, o.total, o.customer.name) from Order o. The class name must be fully qualified, and the class needs a public constructor whose parameter types and order match the selected expressions. Results come back as plain, unmanaged objects.

open as a page

In a JPQL query, how do you write an inner join and a left outer join between two entities, and how do the results differ?

level: juniorimportance: must knowfreq 72%
basics
~20 s

You join an association path, not a table: SELECT a FROM Author a JOIN a.books b. Inner join drops authors with no books; LEFT JOIN keeps them with b as null. The mapping supplies the join columns, so no ON clause is required.

open as a page

What is JPQL, and how does a JPQL query differ from the SQL statement that eventually runs against the database?

level: juniorimportance: must knowfreq 78%
basics
~20 s

JPQL is a query language over the entity model: you name entity classes and their Java field names, not tables and columns. The persistence provider translates it into vendor-specific SQL using the mappings, and returns managed entities rather than rows.

open as a page

In JPA, what is a named query, how do you declare one with the @NamedQuery annotation, and how do you execute it through the EntityManager?

level: juniorimportance: must knowfreq 58%
basics
~20 s

A named query is a JPQL string declared once under a name, usually with @NamedQuery on an entity class. You execute it with entityManager.createNamedQuery("Name", Result.class), bind parameters, then getResultList() or getSingleResult(). The name is global to the persistence unit.

open as a page

Inside one JPA persistence context (a Hibernate Session), you call em.find(Customer.class, 1L) twice. How many SELECT statements does Hibernate issue, and are the two returned references the same Java object?

level: juniorimportance: must knowfreq 68%
basics
~20 s

One SELECT, and the same object both times. The persistence context is an identity map: one managed instance per entity identity for as long as the session lives. It is always on and cannot be disabled; clear() or detach() removes entries.

open as a page

Hibernate's second-level cache does nothing unless you configure it. Walk through everything required to make one entity class actually cached: the configuration properties, the extra library, and the annotations on the class.

level: juniorimportance: must knowfreq 55%
basics
~10 s

Three things. Set hibernate.cache.use_second_level_cache=true. Plug in a RegionFactory backed by a real provider (usually the JCache bridge plus EhCache, Infinispan or Caffeine). Mark the entity with jakarta.persistence.@Cacheable and Hibernate's @Cache.

open as a page

Hibernate has a query cache that is separate from its entity cache. What does it hold, and what two things must be done before a given JPQL query actually uses it?

level: juniorimportance: must knowfreq 48%
basics
~20 s

It caches the results of a query keyed by the query text and its parameters. You must set hibernate.cache.use_query_cache=true globally and mark each query cacheable individually — setCacheable(true) or the org.hibernate.cacheable hint. It also requires the second-level cache.

open as a page

In Hibernate, you put the org.hibernate.annotations.@Cache annotation on an entity's @OneToMany collection field. What does the resulting second-level cache region actually store, and what else has to be cached for that to save database work?

level: middleimportance: must knowfreq 50%
basics
~20 s

Only the element identifiers — an id list keyed by the owner's id, not the children's column data. Hibernate then resolves each id through the element entity's own cache region, so that entity must be cached too or you still hit the database.

open as a page

Hibernate lets you choose a second-level cache concurrency strategy per entity: READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, or TRANSACTIONAL. What consistency does each guarantee, and what kind of data is each meant for?

level: middleimportance: must knowfreq 62%
basics
~20 s

READ_ONLY: never-modified data; updates are rejected; fastest. NONSTRICT_READ_WRITE: no locking, entry evicted on change, short stale window possible. READ_WRITE: soft locks give roughly read-committed consistency for mutable data. TRANSACTIONAL: cache enlists in the JTA transaction; strongest, slowest.

open as a page

Using the JPA EntityManager API directly, walk through what happens between EntityTransaction.begin() and EntityTransaction.commit() — in particular, when does Hibernate actually send INSERT, UPDATE and DELETE statements to the database?

level: juniorimportance: must knowfreq 70%
basics
~20 s

begin() starts one database transaction with JDBC auto-commit off. persist/merge/remove only change in-memory state. commit() first flushes, sending the queued INSERT/UPDATE/DELETE SQL, then issues COMMIT. rollback() sends ROLLBACK and the persistence context must be discarded.

open as a page

In plain JPA/Hibernate, how do you tell the persistence provider to read an entity while holding a database row lock for the rest of the transaction, and what does it actually send to the database?

level: juniorimportance: must knowfreq 55%
basics
~20 s

Pass a pessimistic lock mode on the read: em.find(Order.class, id, LockModeType.PESSIMISTIC_WRITE), query.setLockMode(...), or em.lock(managedEntity, ...). Hibernate emits SELECT ... FOR UPDATE. A transaction must be active, and the database holds the lock until commit or rollback.

open as a page

Inside one Hibernate Session you load a row by primary key, another session commits an update to that row, and you load it by the same primary key again — you still see the old field values. Explain why, and say whether the database isolation level is what produced that behaviour.

level: middleimportance: must knowfreq 55%
basics
~20 s

The persistence context is an identity map keyed by entity type plus id. The second lookup returns the instance already in it without re-reading, so you get repeatable reads at application level regardless of the database isolation level. Only refresh, clear or a new session re-reads.

open as a page

An entity has a field annotated with JPA's @Version. Walk through exactly what SQL Hibernate emits when it flushes a change to that entity, and how it concludes that another transaction modified the row first.

level: middleimportance: must knowfreq 70%
basics
~20 s

Hibernate emits UPDATE t SET cols=?, version = old+1 WHERE id = ? AND version = old. It then reads the JDBC affected-row count. One row means it won; zero rows means someone else already changed the version, so Hibernate raises StaleObjectStateException, surfaced to JPA code as OptimisticLockException.

open as a page

What is the difference between JPA's LockModeType.PESSIMISTIC_READ and LockModeType.PESSIMISTIC_WRITE, and what SQL does Hibernate generate for each?

level: middleimportance: must knowfreq 50%
basics
~20 s

PESSIMISTIC_READ takes a shared lock (SELECT ... FOR SHARE): other readers may also lock it, writers block. PESSIMISTIC_WRITE takes an exclusive lock (SELECT ... FOR UPDATE): nobody else may lock or modify the row. On dialects without shared locks, Hibernate upgrades READ to FOR UPDATE.

open as a page

You find code that loads every row of a table into a List with a JPQL query and then filters and counts it in Java. Why is that a problem, and what should the code do instead?

level: juniorimportance: must knowfreq 55%
basics
~20 s

The database sends every row over the network and Hibernate turns each into a managed entity, so memory and time scale with table size and no index is used. Push the filter, the aggregate and the limit into the query instead.

open as a page

In JPA/Hibernate, how do you make a JPQL/HQL query return instances of your own DTO class instead of managed entity objects, and what must that class provide?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Use a constructor expression: select new com.app.UserDto(u.id, u.name) from User u. Name the class fully qualified and give it a constructor whose parameter types match the selected expressions in order. Results are plain objects, not managed entities.

open as a page

In a plain JPA/Hibernate application, how do you make Hibernate print the SQL statements it executes, and how do you see the actual parameter values instead of the ? placeholders?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Set hibernate.show_sql=true to print to stdout, or better, set the org.hibernate.SQL logger to DEBUG so SQL goes through your logging framework. hibernate.format_sql pretty-prints it. Parameters stay as ? until you enable TRACE on Hibernate's bind-parameter logger.

open as a page

Some teams mark every JPA association fetch = FetchType.EAGER so that 'nothing fails later when the data is needed'. What does that cost at runtime, and what should they do instead?

level: middleimportance: must knowfreq 65%
basics
~20 s

EAGER fetches the association on every load path, even queries that never use it — extra selects per row or cartesian products from joined collections. It cannot be switched off per query. Map everything LAZY and fetch explicitly per use case with fetch joins or entity graphs.

open as a page

What extra work and memory does Hibernate spend on a query that returns managed entity objects, compared with the same query returning a DTO projection?

level: middleimportance: must knowfreq 58%
basics
~20 s

For each managed entity Hibernate builds the instance, keeps it in the persistence context, and stores a second copy of its loaded state for dirty checking. Every flush then compares all of them property by property. A DTO row costs one small object and none of that.

open as a page
Hibernate interview questions & primer · KataJob