Why you should always use hibernate.connection.provider_disables_autocommit for resource-local JPA transactions

(Last Updated On: October 18, 2018)

Introduction

One of my major goals for Hibernate is to make sure we offer all sorts of performance improvements to reduce transaction response time and increase throughput. In Hibernate 5.2.10, we addressed the HHH-11542 Jira issue which allows you now to delay the database connection acquisition for resource-local transactions as well.

In this article, I’m going to explain how Hibernate acquires connections and why you want it to delay this process as long as possible.

Resource-local vs. JTA

In Hibernate, the database connection acquisition, as well as the connection release, are relative to the type of the currently running transaction:

  • resource-local: For JDBC transactions, that operate with a single DataSource, the Connection is acquired right when the transaction starts and is closed when the transaction ends (either commit or rollback)
  • JTA: For XA transactions, that span over multiple DataSources, the Connection is acquired upon executing the first Statement and is released after each Statement execution. The aggressive connection release mechanism can be skipped if the underlying application server allows us to do so.

Delaying the resource-local connection acquisition

Our goal is to make the resource-local transaction behave like JTA and delay the connection acquisition until Hibernate needs to execute the first JDBC Statement of the currently running unit-of-work.

The reason why resource-local transaction requires a database connection from the very beginning can be easily visualized in the following diagram:

Hibernate needs to check the underlying JDBC Connection auto-commit status, and disable it if the Connection is set to auto-commit. This way, Hibernate can control the transaction boundaries and make sure that the unit-of-work JDBC Statements are executed in the context of the same database transaction.

Although this behavior is correct since we cannot know if the auto-commit flag was set or not, we could hint Hibernate to skip this check since we already know that all JDBC Connections run in manual commit mode.

For instance, all enterprise applications already use a connection pooling solution which can disable the auto-commit mode when the database connection is firsts established.

HikariConfig hikariConfig = super.hikariConfig( dataSource );
hikariConfig.setAutoCommit( false );

For this reason, in Hibernate 5.2.10, we introduced the hibernate.connection.provider_disables_autocommit configuration property which tells Hibernate that the underlying JDBC Connections already disabled the auto-commit mode.

Benchmark

To measure the performance advantage of delaying database connection acquisition, we are going to use a test case which emulates a resource-intensive XML document parsing which happens within the boundaries of the JPA transaction context.

If we don’t delay the connection acquisition, the XML parsing duration is going to be added to the database connection lease time. However, once we switch to the new connection delay mechanism, the connection lease time is reduced considerably as illustrated by the graph below.

Therefore, if you are using resource-local transactions (which is quite the norm when using Spring framework), you should definitely configure the connection pool (e.g. HikariCP) to disable the auto-commit commit, and provide the connection acquisition delay Hibernate configuration property:

<property 
    name="hibernate.connection.provider_disables_autocommit"
    value="true"
/>

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.

Conclusion

Hibernate is not just an ORM tool, but a full-blown data access framework. Because database connection management is very important for a high-performance enterprise application, Hibernate allows you to minimize the window of time required to execute a database transaction which leads to a higher transaction throughput as well.

Subscribe to our Newsletter

* indicates required
10 000 readers have found this blog worth following!

If you subscribe to my newsletter, you'll get:
  • A free sample of my Video Course about running Integration tests at warp-speed using Docker and tmpfs
  • 3 chapters from my book, High-Performance Java Persistence, 
  • a 10% discount coupon for my book. 
Get the most out of your persistence layer!

Advertisements

19 thoughts on “Why you should always use hibernate.connection.provider_disables_autocommit for resource-local JPA transactions

  1. Typo in the title:
    Delaying the resource-local connectcion acquisition

    [connectcion]

    Also, really nice topics, thank you for sharing your knowledge Vlad!

  2. Hi Vlad, I am observing very different behaviors with JTA and the connection.handling_mode being set to DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT or not set at all. I have an entity whose multiple instances are being persisted within the same thread, albeit in different Transactions. I observed that when I set the connection.handling_mode to DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT, the session hangs when attempting to execute the JDBC statement, and only completes when the parent transaction eventually times out. But, when I do not have the connection.handling_mode not set, then I noticed that all the instances of the entities were being updated without any issues. Any ideas on what could be the reason?

    https://stackoverflow.com/questions/52485380/hibernate-connection-handling-mode-and-requires-new-transactions-hibernate-5-2

  3. Hi,
    We are trying to implement the feature “provider_disables_autocommit” in our application.
    Problem context in our application: We have a manager class which has complex business logic. We configured HibernateTransactionManager around the methods of manager class.
    In many cases, we simply returns from the manager without touching the database.
    This option of hibernate seems very promising to us. However, we observe there are some caveat with the option.
    1. Though the connection acquisition indeed delayed until it is needed. But in the case where database communication never done, while committing the transaction, hibernate is trying to connect to the database. My question is that, is not it possible that if there has nothing happened during transaction then hibernate simply returns without ever contacting to the database.
    2. To implement this is via spring HibernateTransactionManager, we have to set txManager.setPrepareConnection(false), txManager.setAutodetectDataSource(false) , otherwise it tries to acquire connection when transaction is starting. Is there a negative impact of this?

      1. requires a code change in Hibernate. You could provide a Pull Request with the fix.
      2. There are drawbacks to disabling those flags like not propagating read-only flag to the Session, but this is an optimization that is brought by Spring 5.1. For more details, check out my High-Performance Java Persistence book.
      1. Our main concern is to delay the connection acquisition. To leverage spring optimisation, connection must be acquired which is exactly what we do not want.
        So, if those two settings have only performance impact then we had to live with it.

  4. Vlad, you are saying that setting hibernate.connection.provider_disables_autocommit = true causes Hibernate ORM to postpone acquiring a connection from pool till the very last moment when the first statement in a transaction must be executed. However, the docs http://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/Hibernate_User_Guide.html#configurations-database-connection say that this property just allow hibernate to “to opt-out of certain operations that may have a performance impact (although this impact is generally negligible)”.

    And I can understand the opt-out specified in the docs, but I see no reason why would Hibernate acquire a connection from a pool before it actually needs to execute a statement (this is what you are describing). For example, if we annotated a method with @Transactional(propagation = REQUIRES_NEW) annotation, but have never executed a single statement there, it’s quite obvious that Hibernate have no reason to acquire a connection from a pool. If it actually acquires one, and hibernate.connection.provider_disables_autocommit = true is the only way to change the behaviour, then could you please elaborate why does Hibernate needs to acquire a connection even if we are not using it (I have read your explanation in the article multiple times, but I still don’t think/don’t see it explaining the reason)?

    1. It’s all to make sure the autocommit is disabled since it’s enable by default on a JDBC Connection.

      1. But can’t Hibernate make sure that auto-commit is disabled right before actually executing a statement, instead of doing this right at the beginning of Java-marked transaction scope (potentially, long before executing any statement)? It sure seems like nothing prevents Hibernate to postpone this action until the first statement execution.

      2. I’m not sure whether the logical connection has any knowledge about the underlying Tx type. This behaviour should happen only for RESOURCE_LOCAL, not for JTA. If you think you want to explore it, please send a Pull Request with this feature implemented.

      3. “This behaviour should happen only for RESOURCE_LOCAL” – yes, I got this. You said in HHH-11542: “For RESOURCE_LOCAL transactions, the Connection acquisition is not really delayed until the first Statement is needed to be executed because a Connection is acquired right after the Transaction has started since we need to read the auto-commit flag.”

        And my question is actually very simple and boils down to: why does Hibernate need to read the auto-commit flag right after the RL transaction has started? You say that Hibernate does not need to do this for JTA transaction (seems reasonable), but why is it necessary for RL transaction (I see no difference with regard to the action “read the auto-commit flag”)?

        The question is actually very straightforward, I can’t see why we don’t understand each other 🙂

      4. The Hibernate Session and the JPA EntityManager follows the Unit of Work pattern which cannot work in autocommit mode. Hibernate cannot assume anything about the autocommit flag, so it either sets it to false or it checks it and sets it to false if it’s set to true. Either way, a Connection is needed. While this could be further delayed, it’s just a matter of designing the API. If you think it’s worth implementing what you propose, just send us a Pull Request. That’s how OSS works.

      5. “While this could be further delayed, it’s just a matter of designing the API” – thanks, this answers my question in full. This means that there is no principle reason behind this behaviour (which is what I suspected), it simply was implemented this way.

      6. It’s implemented this way because implementing it differently might not be trivial. Give it a try and you’ll see.

  5. I am opening transaction using TransactionInterceptor and using HibernateTransactionManager and com.zaxxer.hikari.HikariDataSource as datasource.

    I have set autocommit value for datasource and hibernate property hibernate.connection.provider_disables_autocommit values as follows

    true
    Even then the transaction is getting opened much before it is required.

    5.3.1.Final version of hibernate-core is used for the above.

    I have used the following references.

    https://github.com/spring-projects/spring-boot/issues/9261

    https://vladmihalcea.com/why-you-should-always-use-hibernate-connection-provider_disables_autocommit-for-resource-local-jpa-transactions/

    Please let me know in case anything else was required to be done or what is the exact meaning of delay.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.