Hibernate
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 pageshowhide
guide
overview
~1 minHibernate 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.
- Entity Mapping & Annotations →
How classes, identifiers and columns become tables; every later section assumes you can read a mapping and predict its schema.
- Persistence Context & Session →
Entity states, flushing and dirty checking: the engine that explains when Hibernate reads and writes.
- Associations & Fetching →
Relationships, lazy loading and fetch plans, where N+1 selects and lazy-loading failures come from.
- HQL, JPQL & Criteria API →
The query tools, and which of them return managed entities versus plain data or bypass the context.
- Transactions & Locking →
Optimistic versions and row locks, needed for every lost-update scenario an interviewer poses.
- 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
persistormergewrites 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
mergeand editing it afterwards:mergereturns 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/hashCodeon a generated id, so an entity's hash changes when it is persisted while it sits in aHashSet.Choosing IDENTITY generation for a write-heavy table without knowing it prevents Hibernate from batching inserts.
Running a bulk JPQL
UPDATEand 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
- Entity Mapping & Annotations46 questions
- @Entity Basics & Access Types5 questions
- Identifier Generation Strategies5 questions
- Columns & AttributeConverters6 questions
- Embeddables & Composite Keys6 questions
- Enum & Date/Time Mapping6 questions
- Inheritance Strategies5 questions
- Naming Strategies4 questions
- @Formula & Generated Values4 questions
- Entity equals/hashCode & @NaturalId5 questions
- Associations & Fetching45 questions
- Association Kinds & Owning Side5 questions
- Join Columns vs Join Tables5 questions
- Cascade Types & orphanRemoval6 questions
- LAZY vs EAGER Defaults & Proxies5 questions
- The N+1 Problem5 questions
- JOIN FETCH & Entity Graphs4 questions
- @BatchSize & Subselect Fetching5 questions
- LazyInitializationException5 questions
- Persistence Context & Session40 questions
- Entity Lifecycle States5 questions
- persist vs merge vs update5 questions
- Flush Modes & Flush Order4 questions
- Dirty Checking & Write-Behind5 questions
- First-Level Cache & Identity3 questions
- Detached Entities & Their Pitfalls5 questions
- Session vs EntityManager4 questions
- Lifecycle Callbacks & Interceptors5 questions
- Open Session in View Debate4 questions
- HQL, JPQL & Criteria API38 questions
- JPQL & HQL Fundamentals5 questions
- JPQL Joins & Navigation5 questions
- Named Queries4 questions
- Native Queries & Result Mapping4 questions
- Criteria API5 questions
- DTO Projections4 questions
- Pagination & the Fetch-Join Trap6 questions
- Bulk UPDATE/DELETE & Insert-Select5 questions
- Caching28 questions
- L1 vs L2 Cache Scopes4 questions
- Enabling L2 & Providers5 questions
- Cache Concurrency Strategies4 questions
- Query Cache5 questions
- Collection & Natural-Id Caching5 questions
- Invalidation, Clustering & Caveats5 questions
- Transactions & Locking25 questions
- Transaction Integration5 questions
- Optimistic Locking with @Version5 questions
- Versionless Optimistic Locking4 questions
- Pessimistic Locking6 questions
- Isolation Levels & the ORM5 questions
- Performance & Tuning31 questions
- JDBC Batching6 questions
- StatelessSession4 questions
- Read-Only & Streaming Reads5 questions
- Statistics & SQL Logging5 questions
- Entity vs DTO Reads5 questions
- Performance Anti-Pattern Catalog6 questions
questions
253 · 7 sectionsWhat 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?
basics
~20 sMark 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.
What does the JPA @Column annotation control on a simple entity attribute, and what happens to an attribute that carries no @Column at all?
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.
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?
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.
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?
basics
~20 sBy 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.
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?
basics
~20 sObject.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.
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.
basics
~20 sThey 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.
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?
basics
~20 sBy 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.
In JPQL, what does the JOIN FETCH clause do, and how does it differ from writing a plain JOIN in the same query?
basics
~20 sJOIN 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.
In JPA, what does the @JoinColumn annotation declare, and which side of an association must carry it?
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.
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?
basics
~20 sTo-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.
Which JPA entity lifecycle callback annotations exist, and at what point in an entity's lifecycle does each of them fire?
basics
~20 sSeven: @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.
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.
basics
~20 sA 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.
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.
basics
~20 sTransient (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.
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?
basics
~20 sYou 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.
In JPA/Hibernate, what does it mean to "flush" the persistence context, and how is flushing different from committing the transaction?
basics
~20 sFlushing 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.
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?
basics
~20 sEntityManager.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>.
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?
basics
~20 sWrite 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.
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?
basics
~20 sYou 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.
What is JPQL, and how does a JPQL query differ from the SQL statement that eventually runs against the database?
basics
~20 sJPQL 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.
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?
basics
~20 sA 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.
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?
basics
~20 sOne 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.
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.
basics
~10 sThree 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.
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?
basics
~20 sIt 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.
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?
basics
~20 sOnly 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.
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?
basics
~20 sREAD_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.
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?
basics
~20 sbegin() 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.
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?
basics
~20 sPass 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.
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.
basics
~20 sThe 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.
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.
basics
~20 sHibernate 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.
What is the difference between JPA's LockModeType.PESSIMISTIC_READ and LockModeType.PESSIMISTIC_WRITE, and what SQL does Hibernate generate for each?
basics
~20 sPESSIMISTIC_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.
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?
basics
~20 sThe 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.
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?
basics
~20 sUse 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.
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?
basics
~20 sSet 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.
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?
basics
~20 sEAGER 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.
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?
basics
~20 sFor 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.