Announcement Announcement Module
Collapse
No announcement yet.
Multiple commits on SINGLE Hibernate session Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Multiple commits on SINGLE Hibernate session

    Hello,

    I'd like to achieve something like this:
    Code:
    public interface RequestCallback {
      public void onRequest( Request request );
    }
    
    @Transactional
    public void processPendingRequests() { 
      requestDao.iteratePending( new RequestCallback() {
        public void onRequest( Request request ) {
          requestDao.lock( request );
          process( request );
          // I would like a commit here!
        }
      }
    }
    So I've tried:
    Code:
    @Transactional
    public void processPendingRequests() { 
      requestDao.iteratePending( new RequestCallback() {
        public void onRequest( Request request ) {
          TransactionTemplate tt = new TransactionTemplate( transactionManager ) // should be created elsewhere I know;
          tt.execute( new TransactionCallbackWithoutResult() ) {
            @Override
            protected void doInTransactionWithoutResult( TransactionStatus transactionstatus ) {
              requestDao.lock( request );
              process( request );
            }
          }
          // commit does not happen here at all
        }
      }
    }
    // commit happens here
    did not work. So I went to:

    Code:
    @Transactional
    public void processPendingRequests() { 
      requestDao.iteratePending( new RequestCallback() {
        public void onRequest( Request request ) {
          TransactionTemplate tt = new TransactionTemplate( transactionManager ) // should be created elsewhere I know;
          tt.setPropagationBehavior( TransactionDefinition.PROPAGATION_REQUIRES_NEW ); // <--------- opens new hibernate session :(
          tt.execute( new TransactionCallbackWithoutResult() ) {
            @Override
            protected void doInTransactionWithoutResult( TransactionStatus transactionstatus ) {
              requestDao.lock( request );
              process( request );
            }
          }
          // commit does happen here
        }
      }
    }
    Now it works but with every tt.execute I get:
    - main transaction suspended
    - new hibernate session created
    - new transaction created
    - request processed
    - transaction commited
    - session closed
    - main transaction resumed

    I have also tried to manage transactions completely by hand (without use of transaction template and @Transactional interface). Second call to
    transactionManager.commit( transactionStatus ) raised an exception: Transaction is already completed.

    There is totally no problem to do this in pure hibernate. I am lost in Spring's transaction framework.

  • #2
    The problem is the way you are handling transactions. A transaction can be committed/rolledback only once (if I'm not mistaken).

    in your code the processPendingRequests method is transactional, so after the method finishes the transaction is committed.

    Now if you want to handle the transactions your self, first of all remove the @Transactional and use the TransactionTemplate. Your second code snippet was almost correct, the only thing messing things up was the @Transactional annotation.

    Code:
    public void processPendingRequests() { 
      requestDao.iteratePending( new RequestCallback() {
        public void onRequest( Request request ) {
          TransactionTemplate tt = new TransactionTemplate( transactionManager ) // should be created elsewhere I know;
          tt.execute( new TransactionCallbackWithoutResult() ) {
            @Override
            protected void doInTransactionWithoutResult( TransactionStatus transactionstatus ) {
              requestDao.lock( request );
              process( request );
            }
          }
          // commit does happen here
        }
      }
    }

    Comment


    • #3
      1. Concerning "manual" transaction management - even in the pure Hibernate you can not commit the same transaction twice. Yes, you may reuse the session (while it is not very recommended in the Hibernate manual), but not transaction.
        So you need a new txStatus for each call to txManager.commit(txStatus).

      2. You need not (and should not) to use @transactional and Transaction template together in the same method. If your application context is configured properly the whole contents of the method marked with @Transactional is transparently wrapped into the transaction template.

      3. By definition, the whole contents of the marked with @Transactional method or doInTransactionXXX() method is executed in the single transaction, so if you want to have multiply transaction, you need to put only the part of code that constitutes single transaction in the separate method and mark it as @Transactional or make it a body of doInTransactionXXX() method.

      4. Creation of Hibernate session is lightweight operation (it does not assume creation of the new DB session), so you should not be very concerned about it.

      Comment


      • #4
        Originally posted by al0 View Post
        1. You need not (and should not) to use @transactional and Transaction template together in the same method. If your application context is configured properly the whole contents of the method marked with @Transactional is transparently wrapped into the transaction template.
        That one should not be a problem as far as I understand it. It depends on the transaction configuration (PROPAGATION_REQUIRED, etc.) what actually happens. I consider nested transaction logic even as normal. Imagine a service that is used from another service, both are declared to be transactional. You only get a problem if it is not configured properly, PROPAGATION_REQUIRES_NEW would case probably unwanted effects. But that's what the actual propagation properties are there for: To influence the transactional behavior of (nested) transaction logic.

        Jörg

        Comment


        • #5
          Yes, but I have not meant that nesting transaction are bad, I just have pointed out that it is not good style to mix declarative and programmatical transaction management (while technically it absolutely possible) and, even more important, it is absolutely unnecessary for the purpose of orignal poster.

          Concerning nested trasactions - there usage is very dubios, as it is highly DB/Transaction manager dependent (while I should admit that implementation of the REQUIRED_NEW seems to be more or less consistent across them).

          Regards,
          Oleksandr

          Comment


          • #6
            I think conceptually what Marten posted makes more sense anyway. Each iteration is commited as a descrete transaction.
            Last edited by karldmoore; Aug 29th, 2007, 11:51 AM.

            Comment

            Working...
            X