Results 1 to 6 of 6

Thread: Multiple commits on SINGLE Hibernate session

  1. #1
    Join Date
    Aug 2005
    Posts
    14

    Default 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. #2
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,695

    Default

    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
        }
      }
    }
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  3. #3
    Join Date
    Aug 2006
    Location
    Now Germany, previously Ukraine
    Posts
    1,546

    Default

    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.

  4. #4
    Join Date
    Nov 2005
    Location
    Reutlingen, Germany
    Posts
    2,098

    Default

    Quote 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

  5. #5
    Join Date
    Aug 2006
    Location
    Now Germany, previously Ukraine
    Posts
    1,546

    Default

    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

  6. #6
    Join Date
    Sep 2006
    Location
    UK
    Posts
    8,425

    Default

    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 at 10:51 AM.
    Barracuda Networks SSL VPN Lead Developer
    http://pramatr.wordpress.com
    http://twitter.com/karldmoore
    http://www.linkedin.com/in/karldmoore
    Any postings are my own opinion, and should not be attributed to my employer or clients.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •