Hibernate Architecture
|
This section documents Hibernate ORM 7.4.x (User Guide, Introduction, Query Language Guide, Data Repositories Guide), Jakarta Persistence 3.2, Hibernate Search 8.4.x, and the Hibernate Validator / Hibernate Reactive references — which are the references these pages are written and verified against. This content was generated with the assistance of AI and should be verified against those official docs before being relied on in production. Three older reference books were consulted as bibliography only while preparing these pages and are not the
primary or main source for any page. All three predate Jakarta Persistence 3.2 and Hibernate ORM 6/7 (the
This section’s bibliography lists the reference material consulted while preparing these pages. |
Hibernate (JPA & ORM) already introduces the object/relational paradigm mismatch briefly. This page goes deeper into each friction point and lays out where Hibernate’s runtime objects sit relative to JDBC.
The paradigm mismatch, in depth
-
Granularity — an
AddressorMoneyclass is naturally its own type in Java, but rarely its own table; it typically maps onto a handful of columns of the owning entity’s table (@Embeddable, see Basic & Embeddable Types). -
Inheritance — Java’s single-inheritance class hierarchies and interfaces have no direct SQL counterpart. A
Payment/CardPayment/BankTransferPaymenthierarchy has to be flattened onto one of three table shapes — see Inheritance Mapping. -
Identity — Java has three notions of "sameness": reference identity (
==),equals()-defined equality, and database identity (same primary key value). Two separately loadedEntityManagerinstances can each hold a distinct Java object for the same row; a single persistence context, by contrast, guarantees one Java instance per row (the identity map, see Persistence Context & Lifecycle). -
Associations — a Java reference is directional and single-ended; a foreign key is undirected column data navigable from either table. A
@ManyToManyneeds a join table that has no object-model counterpart at all. See Associations. -
Data navigation — walking
order.getCustomer().getAddress().getCity()one reference at a time is natural in Java and disastrous against a database unless the right join (or fetch strategy) accompanies it — the root cause of the N+1 problem, see Fetching & N+1.
Hibernate’s job is to let you program against the object model while it works out the SQL, joins, and identity bookkeeping needed to reconcile it with the relational model underneath.
Layered architecture
Application code talks to either the standard JPA API (EntityManager) or Hibernate’s own native API
(Session, a superset of EntityManager); both sit on top of the same persistence-context machinery, which in
turn generates SQL and delegates to a plain JDBC Connection. Hibernate never talks to the database except
through JDBC — there is no proprietary wire protocol.
SessionFactory/Session vs. EntityManagerFactory/EntityManager
Hibernate’s native API predates JPA and remains richer than it:
| Native type | JPA equivalent | Notes |
|---|---|---|
|
|
One per persistence unit, thread-safe, application-scoped. |
|
|
|
|
|
Hibernate’s |
A JPA-only application never needs to see org.hibernate.* types; reaching for Session (via
entityManager.unwrap(Session.class)) is a deliberate opt-in to Hibernate-specific capability, and ties that
code to Hibernate as the provider.
StatelessSession
StatelessSession is a command-oriented alternative to Session: no persistence context, no first-level
cache, no automatic dirty checking, no cascading, no interceptors/events by default. Every operation
(insert/update/delete/get) is issued immediately as its own SQL statement, and returned entities are
detached the moment they are loaded. It trades away Hibernate’s automation for predictable, low-overhead
behavior — exactly what large batch/ETL jobs want; see
Bulk Operations & Batching.
Persistence units and dialects
A persistence unit names a set of managed classes, a data source, and a bag of properties — the unit of
configuration an EntityManagerFactory is built from (one unit per persistence.xml <persistence-unit>
element, or the equivalent Spring Boot auto-configuration). A dialect (org.hibernate.dialect.Dialect and
its subclasses — PostgreSQLDialect, MySQLDialect, SQLServerDialect, …) tells Hibernate the SQL variant,
pagination syntax, identity/sequence support, and type mappings for one specific database product; since
Hibernate 6 the dialect is auto-detected from the JDBC connection metadata in the overwhelming majority of
cases, so hibernate.dialect rarely needs to be set explicitly.