Hibernate.orgCommunity Documentation

Chapter 7. Transactions and concurrency control

Table of Contents

7.1. Physical Transactions
7.1.1. JTA configuration
7.2. Hibernate Transaction API
7.3. Transactional patterns (and anti-patterns)
7.3.1. Session-per-operation anti-pattern
7.3.2. Session-per-request pattern
7.3.3. Conversations
7.3.4. Session-per-application
7.4. Common issues

It is important to understand that the term transaction has many different yet related meanings in regards to persistence and Object/Relational Mapping. In most use-cases these definitions align, but that is not always the case.

Note

This documentation largely treats the physical and logic notions of transaction as one-in-the-same.

Hibernate uses the JDBC API for persistence. In the world of Java there are 2 well defined mechanism for dealing with transactions in JDBC: JDBC itself and JTA. Hibernate supports both mechanisms for integrating with transactions and allowing applications to manage physical transactions.

Transaction handling per Session is handled by the org.hibernate.resource.transaction.TransactionCoordinator contract, which are built by the org.hibernate.resource.transaction.TransactionCoordinatorBuilder service. TransactionCoordinatorBuilder represents a strategy for dealing with transactions whereas TransactionCoordinator represents one instance of that strategy related to a Session. Which TransactionCoordinatorBuilder implementation to use is defined by the hibernate.transaction.coordinator_class setting.

Note

For details on implementing a custom TransactionCoordinatorBuilder, or simply better understanding how it works, see the Integrations Guide

Hibernate uses JDBC connections and JTA resources directly, without adding any additional locking behavior. Hibernate does not lock objects in memory. The behavior defined by the isolation level of your database transactions does not change when you use Hibernate. The Hibernate Session acts as a transaction-scoped cache providing repeatable reads for lookup by identifier and queries that result in loading entities.

Important

To reduce lock contention in the database, the physical database transaction needs to be as short as possible. Long database transactions prevent your application from scaling to a highly-concurrent load. Do not hold a database transaction open during end-user-level work, but open it after the end-user-level work is finished. This is concept is referred to as transactional write-behind.

Interaction with a JTA system is consolidated behind a single contract named org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform which exposes access to the javax.transaction.TransactionManager and javax.transaction.UserTransaction for that system as well as exposing the ability to register javax.transaction.Synchronization instances, check transaction status, etc.

Hibernate tries to discover the JtaPlatform it should use through the use of another service named org.hibernate.engine.transaction.jta.platform.spi.JtaPlatformResolver. If that resolution does not work, or if you wish to provide a custom implementation you will need to specify the hibernate.transaction.jta.platform setting. Hibernate provides many implementations of the JtaPlatform contract, all with short-names:

Built-in JtaPlatform implementations by short name

  • Borland - JtaPlatform for the Borland Enterprise Server.

  • Bitronix - JtaPlatform for Bitronix.

  • JBossAS - JtaPlatform for Arjuna/JBossTransactions/Narnya when used within the JBoss/WildFly Application Server.

  • JBossTS - JtaPlatform for Arjuna/JBossTransactions/Narnya when used standalone.

  • JOnAS - JtaPlatform for JOTM when used within JOnAS.

  • JOTM - JtaPlatform for JOTM when used standalone.

  • JRun4 - JtaPlatform for the JRun 4 Application Server.

  • OC4J - JtaPlatform for Oracle's OC4J container.

  • Orion - JtaPlatform for the Orion Application Server.

  • Resin - JtaPlatform for the Resin Application Server.

  • SunOne - JtaPlatform for the SunOne Application Server.

  • Weblogic - JtaPlatform for the Weblogic Application Server.

  • WebSphere - JtaPlatform for older versions of the WebSphere Application Server.

  • WebSphereExtended - JtaPlatform for newer versions of the WebSphere Application Server.

Hibernate provides an API for helping to isolate applications from the differences in the underlying physical transaction system in use. Based on the configured TransactionCoordinatorBuilder, Hibernate will simply do the right thing when this transaction API is used by the application. This allows your applications and components to be more portable move around into different environments.

To use this API, you would obtain the org.hibernate.Transaction from the Session.

Transaction allows for all the normal operations you'd expect. begin, commit and rollback. And these calls noop if they should.

It even exposes some cool methods like:

  • markRollbackOnly that works in both JTA and JDBC!
  • getTimeout and setTimeout that again work in both JTA and JDBC!
  • registerSynchronization that allows you to register JTA Synchronizations even in non-JTA environments. In fact in both JTA and JDBC environments, these Synchronizations are kept locally by Hibernate. In JTA environments Hibernate will only ever register one single Synchronization with the TransactionManager to avoid ordering problems.

Additionally it exposes a getStatus method that returns an org.hibernate.resource.transaction.spi.TransactionStatus enum. This method checks with the underling transaction system if needed, so care should be taken to minimize its use; it can have a big performance impact in certain JTA set ups.

Lets take a look at using the Transaction API in the various environments.




In the CMT case we really could have omitted all of the Transaction calls. But the point of the examples was to show that the Transaction API really does insulate your code from the underlying transaction mechanism. In fact if you strip away the comments and the single configruation setting supplied at bootstrap, the code is exactly the same in all 3 examples. In other words, we could develop that code and drop it, as-is, in any of the 3 transaction environments.

The Transaction API tries hard to make the experience consistent across all environments. To that end, it generally defers to the JTA specification when there are differences (for example automatically trying rollback on a failed commit).

This is the most common transaction pattern. The term request here relates to the concept of a system that reacts to a series of requests from a client/user. Web applications are a prime example of this type of system, though certainly not the only one. At the beginning of handling such a request, the application opens a Hibernate Session, starts a transaction, performs all data related work, ends the transaction and closes the Session. The crux of the pattern is the one-to-one relationship between the transaction and the Session.

Within this pattern there is a common technique of defining a current session to simplify the need of passing this Session around to all the application components that may need access to it. Hibernate provides support for this technique through the getCurrentSession method of the SessionFactory. The concept of a "current" session has to have a scope that defines the bounds in which the notion of "current" is valid. This is purpose of the org.hibernate.context.spi.CurrentSessionContext contract. There are 2 reliable defining scopes:

  • First is a JTA transaction because it allows a callback hook to know when it is ending which gives Hibernate a chance to close the Session and clean up. This is represented by the org.hibernate.context.internal.JTASessionContext implementation of the org.hibernate.context.spi.CurrentSessionContext contract. Using this implementation, a Session will be opened the first time getCurrentSession is called within that transaction.

  • Secondly is this application request cycle itself. This is best represented with the org.hibernate.context.internal.ManagedSessionContext implementation of the org.hibernate.context.spi.CurrentSessionContext contract. Here an external component is responsible for managing the lifecycle and scoping of a "current" session. At the start of such a scope, ManagedSessionContext's bind method is called passing in the Session. At the end, its unbind method is called.

    Some common examples of such "external components" include:

    • javax.servlet.Filter implementation

    • AOP interceptor with a pointcut on the service methods

    • A proxy/interception container

Important

The getCurrentSession() method has one downside in a JTA environment. If you use it, after_statement connection release mode is also used by default. Due to a limitation of the JTA specification, Hibernate cannot automatically clean up any unclosed ScrollableResults or Iterator instances returned by scroll() or iterate(). Release the underlying database cursor by calling ScrollableResults.close() or Hibernate.close(Iterator) explicitly from a finally block.

The session-per-request pattern is not the only valid way of designing units of work. Many business processes require a whole series of interactions with the user that are interleaved with database accesses. In web and enterprise applications, it is not acceptable for a database transaction to span a user interaction. Consider the following example:

Even though we have multiple databases access here, from the point of view of the user, this series of steps represents a single unit of work. There are many ways to implement this in your application.

A first naive implementation might keep the Session and database transaction open while the user is editing, using database-level locks to prevent other users from modifying the same data and to guarantee isolation and atomicity. This is an anti-pattern, because lock contention is a bottleneck which will prevent scalability in the future.

Several database transactions are used to implement the conversation. In this case, maintaining isolation of business processes becomes the partial responsibility of the application tier. A single conversation usually spans several database transactions. These multiple database accesses can only be atomic as a whole if only one of these database transactions (typically the last one) stores the updated data. All others only read data. A common way to receive this data is through a wizard-style dialog spanning several request/response cycles. Hibernate includes some features which make this easy to implement.

Automatic Versioning

Hibernate can perform automatic optimistic concurrency control for you. It can automatically detect if a concurrent modification occurred during user think time. Check for this at the end of the conversation.

Detached Objects

If you decide to use the session-per-request pattern, all loaded instances will be in the detached state during user think time. Hibernate allows you to reattach the objects and persist the modifications. The pattern is called session-per-request-with-detached-objects. Automatic versioning is used to isolate concurrent modifications.

Extended Session

The Hibernate Session can be disconnected from the underlying JDBC connection after the database transaction has been committed and reconnected when a new client request occurs. This pattern is known as session-per-conversation and makes even reattachment unnecessary. Automatic versioning is used to isolate concurrent modifications and the Session will not be allowed to flush automatically, only explicitly.

Session-per-request-with-detached-objects and session-per-conversation each have advantages and disadvantages.