Describes the new features and capabilities added to Hibernate ORM in 8.0.
| If migrating from earlier versions, be sure to also check out the Migration Guide for discussion of impactful changes. |
Jakarta Persistence 4.0
This release introduces support for Jakarta Persistence 4.0, including the following headline features:
-
EntityAgent, which finally standardizes Hibernate’sStatelessSession, -
programmatic SQL result set mappings for more elegant native SQL queries,
-
static query annotations for use with Jakarta Data,
-
@Fetchannotation, andFetchOptions for entity graphs, -
settable default fetch mode for collections,
-
streamlined Criteria query API,
-
@ExcludedFromVersioning, -
@EntityListenerand related improvements to lifecycle callback listeners, -
Criteria query creation from HQL,
-
Statementand related APIs, clearly distinguishing statements which modify data from queries which return data, along withStatementOrTypedQueryas a migration path for existing code, -
improved
StoredProcedureQuery, -
specialized
Optiontypes forEntityManager,EntityAgent,TypedQuery,Statement,StoredProcedureQuery, andCreationOptiontypes forEntityManagerandEntityAgent.
See our blog for discussion of the changes in version 4.0.
Jakarta Data 1.1
Hibernate Data Repositories now implements Jakarta Data 1.1, including support for:
-
integration with JPA4 static queries, including
@QueryOptions, -
restrictions and constraints,
-
@Selectprojections -
stateful repositories, and
-
asynchronous repositories backed by Jakarta Concurrency or Hibernate Reactive.
Graph-based Flushing
8.0 introduces graph-based flush coordination that plans insert, update, delete, and collection work using the mapped relational constraints of the domain model. Instead of relying primarily on operation ordering heuristics, the graph queue builds a dependency model for each flush and executes work in an order that better reflects foreign keys, uniqueness constraints, optional tables, secondary tables, and other mapping relationships.
The goal is both correctness and performance: fewer special-case ordering failures, more predictable batching, and a clearer foundation for future flush-time optimizations. The new graph approach is designed to handle complex object graphs more naturally, especially in applications with deeply related entities, mixed entity and collection changes, and database schemas where constraint ordering matters.
The new graph-based flush coordination is enabled by default, but the legacy strategy remains temporarily available by configuration using
hibernate.flush.queue.type=legacy
org.hibernate.cfg.FlushSettings defines a number of new settings for controlling the graph-based flush coordination.
Improvements to ProcedureCall
In addition to the Jakarta Persistence 4.0 API enhancements to StoredProcedureQuery, a number of improvements and additions have been made to Hibernate’s
ProcedureCall, ProcedureOutputs and Output.
Output Casting
Previous versions of Hibernate required explicit casting of the Output references. E.g.
ProcedureCall call = session.createProcedureCall( "getRegionsAndInitiatives", Region.class);
ProcedureOutputs outputs = call.getOutputs();
List<Region> regions = ( (ResultSetOutput<Region>) outputs.getCurrent() )
.getResultList();
8.0 offers method-driven casting -
ProcedureCall call = session.createProcedureCall( "getRegionsAndInitiatives");
ProcedureOutputs outputs = call.getOutputs();
List<Region> regions = outputs.getCurrent()
.asResultSetOutput( Region.class )
.getResultList();
ResultSet Mapping
Building on top of fixing a long-standing bug and the improvements to output casting, 8.0 adds the ability to lazily declare ResultSet mapping rather than up front during ProcedureCall creation.
var call = session.createProcedureCall( "getRegionsAndInitiatives");
var outputs = call.getOutputs();
List<Region> regions = outputs.getCurrent()
.asResultSetOutput(Region.class)
.getResultList();
outputs.goToNext();
List<Initiative> initiatives = outputs.getCurrent()
.asResultSetOutput(Initiative.class)
.getResultList();
Discriminator-Based Multi-Tenancy and Row-Level Security
On databases with built-in support for row-level security, Hibernate now uses row-level security to enforce the visibility rules implied by discriminator-based multi-tenancy.
In this release, row-level security is already supported on PostgreSQL, Db2, SQL Server, and CockroachDB.
Session and Query Options
Jakarta Persistence 4.0 features the ability to specify type safe vendor-specific options directly from the Jakarta Persistence API.
Session Creation Options
Implementations of EntityManager.CreationOption and EntityAgent.CreationOption define options specified during creation of the stateful or stateless session. Hibernate supports the following creation options:
-
org.hibernate.SessionCreationOption.TenantId -
org.hibernate.SessionCreationOption.EffectiveChangeset -
org.hibernate.SessionCreationOption.EffectiveAt -
org.hibernate.SessionCreationOption.EnabledFilter -
org.hibernate.SessionCreationOption.FetchBatchSize -
org.hibernate.SessionCreationOption.PreferredFetchMethod -
org.hibernate.SessionCreationOption.JdbcBatchSize -
org.hibernate.StatementObserver(see StatementObserver) -
org.hibernate.Interceptor -
jakarta.persistence.SynchronizationType
Session Options
Implementations of EntityManager.Option and EntityAgent.Option define settings which are mutable throughout the lifetime of the session or stateless session, though they may also be used as creation options:
-
org.hibernate.CacheMode -
jakarta.persistence.CacheStoreMode -
jakarta.persistence.CacheRetrieveMode -
org.hibernate.FlushMode -
jakarta.persistence.FlushModeType -
org.hibernate.BatchSize -
org.hibernate.ReadOnlyMode -
org.hibernate.EnabledFetchProfile
E.g.
var entityManager = entityManagerFactory.createEntityManager(
new TenantId("acme"),
new EffectiveAt(now().minus(1,YEARS)),
ReadOnlyMode.READ_ONLY
);
Query Options
Finally, implementations of TypedQuery.Option and Statement.Option define settings affecting the execution of queries and statements:
-
org.hibernate.query.QueryOption.ResultSetCache -
org.hibernate.query.QueryOption.JdbcFetchSize -
org.hibernate.query.QueryOption.Comment -
org.hibernate.EnabledFetchProfile -
org.hibernate.ReadOnlyMode -
org.hibernate.CacheMode -
jakarta.persistence.CacheStoreMode -
jakarta.persistence.CacheRetrieveMode -
jakarta.persistence.QueryFlushMode -
jakarta.persistence.LockModeType -
jakarta.persistence.PessimisticLockScope
getReference() by Natural Id
8.0 adds the ability to get a reference (Session#getReference) based on the natural id of an entity.
var isbn = ...;
var book = session.getReference(Book.class, isbn, KeyType.NATURAL);
StatementObserver
8.0 introduces the new StatementObserver contract, allowing observation of all JDBC statements Hibernate performs.
Safe Mode Validator
8.0 introduces an opt-in "safe mode" for HQL and Criteria queries, designed to restrict potentially unsafe query operations. This feature is particularly valuable for applications that expose Hibernate’s SessionFactory to Large Language Models (LLMs) through various integrations, as well as for security-conscious organizations and multi-tenant applications.
When safe mode is enabled, Hibernate blocks the following operations:
-
The
sql()function - prevents arbitrary SQL syntax execution at runtime -
The
function()function - blocks explicit arbitrary function calls -
The
column()function - prevents arbitrary table column access -
Unknown function calls - Hibernate will reject any function call that hasn’t been explicitly registered with the
Dialect
To use custom functions in safe mode, they must be explicitly registered via org.hibernate.boot.model.FunctionContributor.
Safe mode is disabled by default and can be enabled using:
hibernate.query.safe_mode_enabled=true
When safe mode is enabled and an unsafe operation is attempted, Hibernate throws an exception indicating which function or operation is not allowed.
Flush-Time Bidirectionality Management
Hibernate can now optionally manage bidirectional associations in the managed object graph during flush preparation. When enabled with hibernate.bidirectionality_management=true, Hibernate treats the owning side as authoritative and synchronizes inverse-side references and initialized collections for managed entities as if application code had made those inverse-side changes before flushing.
Uninitialized lazy inverse collections are not initialized solely for bidirectionality management. This is also the important second-level cache boundary: initialized inverse collections participate in normal flush processing and collection cache invalidation, but uninitialized inverse collections are not dirtied or evicted by bidirectionality management alone. If an application changes only the owning side while a cacheable inverse collection remains unloaded, hibernate.cache.auto_evict_collection_cache=true is still the setting which evicts that inverse collection cache entry.
The deprecated bytecode-enhancement setting hibernate.enhancer.enableAssociationManagement=true is also recognized as an alias when the new setting is not specified, making migration to the runtime model straightforward.
|
Subselect Fetching
The following major enhancements were made to subselect fetching.
-
To-one associations are now eligible for bulk select fetching. Previously, only many-valued associations could be fetched in bulk.
-
FetchMethodwas introduced as a JPA 4FetchOptionenumerating the basic fetching methodsBY_ID,JOIN, andBY_SUBQUERY. To request bulk select fetching for anAttributeNodeof anEntityGraph, callnode.addOption(FetchMethod.BY_SUBQUERY).Note that batch fetching may be requested using the standard JPA 4 fetch option
BatchSize.
These changes finally make bulk select fetching a first-class citizen.