Uploaded image for project: 'Hibernate ORM'
  1. HHH-13076

Hibernate “Transaction already active” behaviour with custom transaction manager

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects versions: 5.2.0
    • Fix versions: 5.4.0.CR1, 5.3.8
    • Components: hibernate-core
    • Labels:
      None
    • Bug Testcase Reminder (view):

      Bug reports should generally be accompanied by a test case!

    • Worked in:
    • backPortable:
      Backport?
    • Last commented by a user?:
      true
    • Sprint:

      Description

      While migrating from Hibernate 4.x to latest Hibernate 5 version, I'm encountering an issue with regards to transaction management.

      In our code (actually a unit test), there is a transaction manager that begins a JTA transaction, followed by a sequence of multiple invocations of a method that call to creates a Session to do a save (in which a beginTransaction() is done). Below is an example that reproduces the issue (the scenario is not using Spring or any other container managed transaction management):

      transactionManager.begin();
      saveOrUpdate(entity1);
      saveOrUpdate(entity2);
      ...
      transactionManager.commit();
      
      private void saveOrUpdate(SomeEntity entity) {
          try (Session session = sessionFactory.openSession()) {
              session.setFlushMode(FlushMode.AUTO);
              session.beginTransaction();   // throws IllegalStateException "Transaction already active"
              try {
                  session.saveOrUpdate(entity);
                  session.getTransaction().commit();
              } catch (Exception ex) {
                  session.getTransaction().rollback();
                  throw RuntimeException(ex);
              }
          }
      }
      

      This is causing an IllegalStateException to be thrown with the message "Transaction already active". This behavior seems to have been introduced in Hibernate 5.2.0 (this is the commit) to comply with JPA's EntityTransaction. Previously, Hibernate just ignored the beginning the physical transaction itself because it knows an enclosing transaction is present: it just creates a wrapper JtaTransaction with isInitiator set to false.

      This exception is thrown in org.hibernate.engine.transaction.internal.TransactionImpl, specifically the begin() method:

      @Override
      public void begin() {
          if ( !session.isOpen() ) {
              throw new IllegalStateException( "Cannot begin Transaction on closed Session/EntityManager" );
          }
      
          if ( transactionDriverControl == null ) {
              transactionDriverControl = transactionCoordinator.getTransactionDriverControl();
          }
      
          // per-JPA
          if ( isActive() ) {   // *** This is the problematic part *** //
              throw new IllegalStateException( "Transaction already active" );
          }
      
          LOG.debug( "begin" );
      
          this.transactionDriverControl.begin();
      }
      

      This contradicts with the user manual, where it says the below:

      / Note: depending on the JtaPlatform used and some optional settings,
      // the underlying transactions here will be controlled through either
      // the JTA TransactionManager or UserTransaction
      
      Session session = sessionFactory.openSession();
      try {
          // Assuming a JTA transaction is not already active,
          // this call the TM/UT begin method.  If a JTA
          // transaction is already active, we remember that
          // the Transaction associated with the Session did
          // not "initiate" the JTA transaction and will later
          // nop-op the commit and rollback calls...
          session.getTransaction().begin();
      

      Is there a way to restore the old behavior? Our code relies on such a custom TM scenario. It would be great to have your feedback on this.

        Attachments

        1. MyJtaTransaction.java
          1 kB
        2. MyJtaTransactionManager.java
          4 kB
        3. ORMUnitTestCase.java
          4 kB
        4. SomeEntity.java
          0.7 kB

          Issue links

            Activity

              People

              • Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: