How does aggressive connection release work in Hibernate
Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?
Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.
So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!
Hibernate connection providers
Hibernate needs to operate both in Java EE and stand-alone environments, and the database connectivity configuration can be done either declaratively or programmatically.
To accommodate JDBC Driver
connections as well as RESOURCE_LOCAL and JTA DataSource
configurations, Hibernate defines its own connection factory abstraction, represented by the org.hibernate.engine.jdbc.connections.spi.ConnectionProvider
interface.
public interface ConnectionProvider extends Service, Wrapped { public Connection getConnection() throws SQLException; public void closeConnection(Connection connection) throws SQLException; public boolean supportsAggressiveRelease(); }
Because the connection provider might influence transaction response time, Hibernate offers multiple implementations for the ConnectionProvider
interface:
DriverManagerConnectionProvider
– which uses a rudimentary connection pooling implementation, so it’s only meant for testing scenariosC3P0ConnectionProvider
– uses c3p0 for connection pooling and it’s a much better alternative than the previous optionDatasourceConnectionProvider
– the most flexible choice is to use an externally configuredDataSource
and provide it to Hibernate through thenon-jta-data-source
or ajta-data-source
element, or by setting thehibernate.connection.datasource
configuration property.
The DatasourceConnectionProvider
is the most flexible alternative because it allows proxying the DataSource
with connection pooling, connection monitoring and statement logging semantics in a transparent manner.
Hibernate connection release modes
Hibernate defers the database connection acquisition until the current transaction has to execute its first SQL statement (either triggered by a read or a write operation). This optimization allows Hibernate to reduce the physical transaction interval, therefore increasing the chance of getting a connection from the pool.
The connection release strategy is controlled through the hibernate.connection.release_mode
property which can take the following values:
Value | Description |
---|---|
after_transaction |
Once acquired, the database connection is released only after the current transaction either commits or rolls back. |
after_statement |
The connection is released after each statement execution and reacquired prior to running the next statement. Although not required by either JDBC or JTA specifications, this strategy is meant to prevent application servers from mistakenly detecting a connection leak between successive EJB (Enterprise Java Beans) calls |
auto |
This is the default value, and for RESOURCE_LOCAL transactions it uses the after_transaction mode, while for JTA transactions it falls back to after_statement . |
For more details about why aggresive connection release mode was introduced, check out the HHH-1287 Hibernate Jira issue.
For JTA transactions, the default mode might be too strict since not all Java EE application servers exhibit the same behavior for managing transactional resources. This way, it’s important to check if database connections can be closed outside of the EJB component that triggered the connection acquisition event. Spring-based enterprise systems don’t use Enterprise Java Beans, and, even when using a stand-alone JTA transaction manager, the after_transaction
connection release mode might be just fine.
It’s somehow intuitive that the after_statement
mode incurs some performance penalty associated with the frequent acquisition/releasing connection cycles. For this reason, the following test measures the connection acquisition overhead when using Bitronix in a Spring application context. Each transaction executes the same statement (fetching the current timestamp) for a given number of times (represented on the x-axis).
The y-axis captures the recorded transaction response times for both after_statement
and after_transaction
connection release modes.
The more statements a transaction will execute, the greater the penalty of reacquiring the associated database connection from the underlying connection pool. To better visualize the connection acquisition overhead, the test runs up to 10000 statements, even if this number is probably too high for the typical OLTP transaction.
Ideally, database transactions should be as short as possible, and the number of statements shouldn’t be too high either. This requirement stems from the fact that the number of pooled connections is limited and locks are better released sooner than later.
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
The after_transaction
connection release mode is more efficient than the default JTA after_statement
strategy, and so it should be used if the JTA transaction resource management logic doesn’t interfere with this connection releasing strategy.
