Transactions
|
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 never commits or rolls back a database change on its own — every write is scoped to an explicit transaction. This page covers the two transaction models Hibernate supports natively and how a session’s lifetime is usually scoped to one.
Resource-local vs. JTA
-
Resource-local — the simplest model: one
EntityManager/Sessiontalks to exactly oneDataSource/JDBC connection, and the transaction is demarcated directly against it (EntityTransaction/Hibernate’sTransaction). No transaction manager or application server involvement.persistence.xml’s `transaction-type="RESOURCE_LOCAL"selects this. -
JTA — a container-managed, potentially distributed transaction spanning multiple resources (two databases, a database and a JMS queue) coordinated by a
jakarta.transaction.UserTransaction/TransactionManager. Hibernate participates by registering a synchronization with the JTA transaction rather than owning commit/rollback itself.transaction-type="JTA"selects this; it needs an application server or a standalone JTA provider (Narayana, Atomikos, Bitronix).
Spring Boot applications almost always use resource-local transactions under the hood (via
DataSourceTransactionManager/JpaTransactionManager) even though the application code only ever sees
@Transactional — see Spring Data JPA's
@Transactional/propagation section for how Spring’s declarative model maps onto this.
The Hibernate transaction API
Resource-local, using the JPA EntityTransaction:
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
Book book = em.find(Book.class, id);
book.setTitle("New title");
em.getTransaction().commit();
} catch (RuntimeException e) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
throw e;
} finally {
em.close();
}
The native Hibernate API (session.beginTransaction() / Transaction.commit() / Transaction.rollback()) is
functionally equivalent for resource-local use and additionally exposes Transaction.registerSynchronization(…)
for hooking into the commit/rollback lifecycle without a full JTA setup.
Session-per-request and contextual sessions
The recommended session-scoping pattern — one Session/EntityManager per logical unit of work, typically one
HTTP request or one message-processing invocation, opened at the start and closed at the end — rather than one
long-lived session for the whole application or one per entity. A long-lived session accumulates managed
entities indefinitely (unbounded first-level-cache growth, stale snapshots) and turns every stray lazy-load
into a LazyInitializationException risk once the caller assumes it is still attached.
Hibernate can also expose a contextual current session (sessionFactory.getCurrentSession()) whose lifetime
and scope is delegated to a pluggable CurrentSessionContext strategy configured via
hibernate.current_session_context_class — thread (one session per thread, the default outside a container),
jta (bound to the active JTA transaction), or a container-specific implementation. Frameworks (Spring) usually
supply their own strategy rather than using this mechanism directly, since they already own request/transaction
scoping.
Rollback and the persistence context
A transaction rollback does not automatically revert in-memory entity state to match the database — Hibernate leaves the persistence context as-is after a rollback, now representing state that was never
committed. JPA’s own rule of thumb applies: after a rollback, the EntityManager should be treated as
unusable and discarded (a new one obtained) rather than reused, precisely because its in-memory entities no
longer reliably reflect the database. EntityManager.clear() mitigates this for entity state, but the
persistence context’s own internal bookkeeping is not guaranteed consistent afterward — discarding it is the
robust choice, and is exactly what session-per-request scoping already does naturally.
Links
-
Transaction Isolation & Locking — where Spring’s
@Transactionaland isolation levels fit above this layer.