Hibernate & Spring Boot Integration
|
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. |
Every other page in this section documents Hibernate on its own terms — plain Jakarta Persistence, independent of any framework. This page is the deliberate exception: it answers the question every reader arriving from the SpringBoot Reference eventually asks — what, exactly, is Spring Data JPA adding on top of Hibernate, and where does Hibernate stop and Spring start?
Two layers, not two competing choices
Spring Data JPA does not replace Hibernate — it sits on top of it. Spring Boot’s
spring-boot-starter-data-jpa pulls in Hibernate ORM as the default Jakarta Persistence provider, Spring ORM,
and a connection pool (HikariCP), then auto-configures an EntityManagerFactory from spring.datasource. and
spring.jpa. — HibernateJpaVendorAdapter is the adapter Boot uses to plug Hibernate in as that provider and
translate common settings (dialect detection, DDL mode) into Hibernate properties. Every entity mapping
annotation (@Entity, @ManyToOne, @Id), every flush, every piece of dirty-checking and every SQL statement
Spring Data JPA ultimately issues is Hibernate doing the actual ORM work — see
Hibernate (JPA & ORM) — Spring Boot
integration for that wiring in full, and Getting Started for
Hibernate’s own bootstrap outside of Spring entirely.
Spring Data JPA, covered in depth in Spring Data JPA, is a
repository-generation layer: it takes an interface (JpaRepository<Book, Long>) and generates an
implementation at startup, backed by an EntityManager obtained from that same Hibernate-provided
EntityManagerFactory. Nothing about Hibernate’s own model — the persistence context, entity states, dirty
checking, caching, HQL — changes underneath it; Spring Data JPA just removes the boilerplate of writing a DAO
class by hand.
| Hibernate (native / plain JPA) | Spring Data JPA | |
|---|---|---|
What it is |
The ORM engine and Jakarta Persistence provider — entity mapping, the persistence context, dirty checking, caching, query execution. |
A repository-generation layer built on top of a JPA provider (Hibernate, by default in Spring Boot). |
How you use it |
Inject/obtain an |
Declare a repository interface; Spring Data generates the CRUD/query implementation at startup. |
Boilerplate for common CRUD |
You write the |
None — |
Deriving a query from intent |
Not built in — write HQL/JPQL, Criteria, or native SQL by hand (HQL/JPQL, Criteria API). |
Derived query methods parse a query straight out of a method name/ |
Type-safe, runtime-composed queries |
The JPA Criteria API / |
Specifications, built on the same Criteria API underneath — no separate query engine. |
Transaction demarcation |
Programmatic ( |
|
Auditing ( |
Manual, via lifecycle callbacks (Events, Interceptors & Filters) or Envers for full history (Envers Auditing). |
|
Testing without a framework |
Bootstrap a |
Needs Spring’s test support ( |
Escape hatch for what the abstraction doesn’t cover |
None needed — you already have the full session/ |
Inject a raw |
Reactive (non-blocking) support |
Only via the separate Hibernate Reactive project, with a fundamentally different session/transaction model — Reactive & Data Repositories. |
None — Spring Data JPA is JDBC-based and always blocking; Spring’s reactive stack uses R2DBC instead, with no Hibernate involved at all. |
The practical guidance: reach for Spring Data JPA’s repositories for the large majority of CRUD and
query-by-intent use cases — it is the lower-friction default this repo’s own
Spring Data JPA page assumes. Drop to the Hibernate/JPA APIs this
section documents in depth (a raw EntityManager, StatelessSession, HQL written by hand, @EntityGraph
tuning) whenever a repository method can’t express what’s needed — Spring Data JPA never hides or blocks that
escape hatch, since the EntityManager it hands your custom repository methods is the very same Hibernate
Session underneath.
Hibernate’s limitations inside a Spring Boot application
These are constraints that come from Hibernate itself, not from Spring Data JPA’s repository layer — they
apply equally whether the code in front of them is a hand-written EntityManager call or a generated
repository method:
-
spring.jpa.open-in-viewhides N+1 problems until production load. It defaults totrue, keeping the persistence context open for the whole HTTP request so lazy associations still resolve in the view/serializer — convenient, but it holds a database connection for longer than the service method and masks N+1 query patterns that only show up as latency under real traffic. See Fetching & N+1 and Hibernate (JPA & ORM) — Spring Boot integration. -
Hibernate is fundamentally blocking. It is built on JDBC, which is a synchronous, thread-blocking API — there is no non-blocking code path through
spring-boot-starter-data-jpa/Hibernate ORM at all. A Spring WebFlux application cannot call aJpaRepository(or a plainEntityManager) from a reactive pipeline without blocking the calling thread; the only genuinely non-blocking path to a JPA-mapped domain model is the separate Hibernate Reactive project, whose session/transaction model does not ride the same ReactorContextSpring’s own reactive transactions use — see Reactive & Data Repositories and Reactive Programming with Project Reactor for the two context-propagation models side by side, and why bridging between them is not automatic. -
The second-level cache is opt-in and easy to leave misconfigured. Unlike Spring’s own
@Cacheableabstraction, Hibernate’s own entity/collection/query cache ( Second-Level Cache) needs a provider dependency and per-entity@Cacheannotations; addingspring-boot-starter-cachealone does nothing for it. The two caching layers solve different problems and are easy to conflate — see the cross-reference on that page and Caching for Spring’s own abstraction. -
Not every Hibernate setting has a first-class Spring Boot property.
HibernateJpaVendorAdapteronly translates the common ones (dialect detection, DDL mode); anything else — batch size, statistics, a Hibernate-specific interceptor — goes through thespring.jpa.properties.hibernate.*prefix (e.g.spring.jpa.properties.hibernate.jdbc.batch_size), which is a raw pass-through with no Boot-side validation or IDE autocompletion. -
Schema generation is a Hibernate-only development convenience, never a Spring Boot feature.
spring.jpa.hibernate.ddl-auto(Boot’s property for Hibernate’shbm2ddl.auto) is documented in full, including whyvalidateis the only production-safe value, on Schema Generation and Tooling. Real schema change belongs to a migration tool instead — see Evolving the Database Model for tracking the database model’s evolution with Liquibase, Mongock, or Flamingock, applied the same way regardless of whether Hibernate is used through Spring Data JPA or on its own.
Links
-
Hibernate (JPA & ORM) — the SpringBoot-side conceptual overview this page assumes as background.
-
Spring Data JPA — the repository-level API in full.
-
Evolving the Database Model — migration tools that should own the schema in staging/production.