Announcement Announcement Module
Collapse
No announcement yet.
<persistence-context> - @Transactional - commit Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • <persistence-context> - @Transactional - commit

    Hi all,

    For one part of my application I have all JPA mappings setup for Lazy loading.
    The only working solution to keep a Hibernate Session open during requests I have found is using the <persistence-context> element.

    I have a view which allows the user to modify some data via Ajax.
    If now my service layer is annotated with @Transactional changes made during Ajax requests are committed to the database e.g. after executing a find method.
    During debugging I have seen it happens in the TransactionInterceptor within the below code fragement:
    Code:
    		if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {
    			// Standard transaction demarcation with getTransaction and commit/rollback calls.
    			TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);
    			Object retVal = null;
    			try {
    				// This is an around advice: Invoke the next interceptor in the chain.
    				// This will normally result in a target object being invoked.
    				retVal = invocation.proceed();
    			}
    			catch (Throwable ex) {
    				// target invocation exception
    				completeTransactionAfterThrowing(txInfo, ex);
    				throw ex;
    			}
    			finally {
    				cleanupTransactionInfo(txInfo);
    			}
    			commitTransactionAfterReturning(txInfo);
    			return retVal;
    		}
    In the data access forum I have found the thread http://forum.springframework.org/showthread.php?t=50586 which points to flushing of hibernate. This would explain why changes are committed during find methods.

    If I remove the @Transactional annotation it's working as intended (changes are only committed at the end of the flow).

    Can I somehow define my transactional annotations that they do not commit in case I'm using <persistence-context>?

    Is somebody more familiar with Hibernate and knows if that is the normal behavior or how to change it?

    How does the <persitence-context> achieve it to not have the same behavior?

    Thanks for any support.

    - Peter

  • #2
    Peter,

    Thanks for posting in my thread. I have since resolved the problem I was experiancing and may be able to help you as well.

    The code you posted above is executed when some database read/write happens outside of a transaction. In this case the open hibernate session will be flushed, breaking any current transactions you have got.

    It's important that all your data access methods are in managed beans and are wrapped in suitable transactions.

    Post your code and I will see if I can spot the same mistake I was making.

    -Paul

    Comment


    • #3
      Hi Paul,

      Thanks for your quick answer and your support.

      My code looks like:

      Spring Webflow action call:
      Code:
      <on-render>
      	<evaluate expression="businessObjectNavigator.reload()"/>
      	<evaluate expression="businessObjectNavigator.getSearchResultContent()" result="flowScope.content" result-type="dataModel"/>
      </on-render>
      Method reload:

      Code:
      public void reload()
      {
      	getEntityServiceBusinessObject().find(searchCriteriaBusinessObjects);
      	initContent();
      }
      Class definiton EntityServiceBusinessObject:

      Code:
      @Service("entityServiceBusinessObject")
      @Transactional(propagation=Propagation.REQUIRED)
      public class EntityServiceBusinessObject implements IEntityServiceBusinessObject {
      Method find:

      Code:
      public List<BusinessObject> find(ISearchCriteriaBusinessObjects searchCriteriaBusinessObjects) {
      	return getBusinessObjectDao().find(searchCriteriaBusinessObjects);
      }
      Class definition BusinessObjectDao:

      Code:
      @Repository("businessObjectDao")
      @Transactional(propagation=Propagation.REQUIRED)
      public class BusinessObjectDao implements IBusinessObjectDao {
      The debug during an operation with the described "by the way save effect":
      Code:
      DEBUG: org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.orm.hibernate3.SessionHolder@b47e5b] for key [org.hibernate.impl.SessionFactoryImpl@c405f] to thread [http-8080-5]
      DEBUG: org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@b47e5b] for key [org.hibernate.impl.SessionFactoryImpl@c405f] bound to thread [http-8080-5]
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Found thread-bound Session [org.hibernate.impl.SessionImpl@c6b865] for Hibernate transaction
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Using transaction object [org.springframework.orm.hibernate3.HibernateTransactionManager$HibernateTransactionObject@73f04f]
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Creating new transaction with name [ch.delos.it.bd.services.masterdata.entity.EntityServiceBusinessObject.find]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@c6b865]
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [oracle.jdbc.driver.T4CConnection@1a5f5a5]
      DEBUG: org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@a22fc4] for key [[email protected]85] to thread [http-8080-5]
      DEBUG: org.springframework.transaction.support.TransactionSynchronizationManager - Initializing transaction synchronization
      DEBUG: org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@b47e5b] for key [org.hibernate.impl.SessionFactoryImpl@c405f] bound to thread [http-8080-5]
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Found thread-bound Session [org.hibernate.impl.SessionImpl@c6b865] for Hibernate transaction
      DEBUG: org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@a22fc4] for key [[email protected]85] bound to thread [http-8080-5]
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Using transaction object [org.springframework.orm.hibernate3.HibernateTransactionManager$HibernateTransactionObject@1edf564]
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Participating in existing transaction
      DEBUG: org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@b47e5b] for key [org.hibernate.impl.SessionFactoryImpl@c405f] bound to thread [http-8080-5]
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Triggering beforeCommit synchronization
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Triggering beforeCompletion synchronization
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Initiating transaction commit
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@c6b865]
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Triggering afterCommit synchronization
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Triggering afterCompletion synchronization
      DEBUG: org.springframework.transaction.support.TransactionSynchronizationManager - Clearing transaction synchronization
      DEBUG: org.springframework.transaction.support.TransactionSynchronizationManager - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@a22fc4] for key [[email protected]85] from thread [http-8080-5]
      DEBUG: org.springframework.orm.hibernate3.HibernateTransactionManager - Not closing pre-bound Hibernate Session [org.hibernate.impl.SessionImpl@c6b865] after transaction
      DEBUG: org.springframework.transaction.support.TransactionSynchronizationManager - Removed value [org.springframework.orm.hibernate3.SessionHolder@b47e5b] for key [org.hibernate.impl.SessionFactoryImpl@c405f] from thread [http-8080-5]
      The code you posted above is executed when some database read/write happens outside of a transaction. In this case the open hibernate session will be flushed, breaking any current transactions you have got.
      Does this only mean in case the operation is not in a transaction at all or also in case outside of an existing transation? I assume the <persistence-context> feature of Spring Webflow will also have a transaction open but it is not joined by the Transactionmanager because if I make the below change in my EnityService:

      Code:
      @Transactional(propagation=Propagation.MANDATORY)
      public List<BusinessObject> find(ISearchCriteriaBusinessObjects searchCriteriaBusinessObjects) {
      	return getBusinessObjectDao().find(searchCriteriaBusinessObjects);
      }
      it is resulting in:

      No existing transaction found for transaction marked with propagation 'mandatory'

      - Peter

      Comment


      • #4
        From the code you have posted I would not have expected txAttr == null to be true in TransactionInterceptor, when calling your "find" method.

        I do have one idea you can try. Make sure that readOnly=true for all your data access methods.

        Code:
        @Transactional(readOnly=true)
        public List<BusinessObject> find(ISearchCriteriaBusinessObjects searchCriteriaBusinessObjects) {
        	return getBusinessObjectDao().find(searchCriteriaBusinessObjects);
        }
        If that doesn't help then I'm out of ideas for now. Your code actually looks very similar to my own, apart from the readOnly attribute on @Transactional.

        Comment


        • #5
          Thanks again for the quick answer.

          Originally posted by Irons UK View Post
          From the code you have posted I would not have expected txAttr == null to be true in TransactionInterceptor, when calling your "find" method.
          The txAttr is not null but the or part
          !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)
          returns false.
          Code:
          if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager))
          I'm using
          org.springframework.orm.hibernate3.HibernateTransa ctionManager

          and checked the class signature:

          Code:
          public class HibernateTransactionManager extends AbstractPlatformTransactionManager
          		implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
          The readOnly attribute I have already tried without success.

          - Peter

          Comment


          • #6
            I have re-tried the readOnly=true attribute because I was not sure if I have placed it on the Service and the Dao classes.
            The find method call does now result in no update on the database!

            During the debugging exactly the same code is execute in the TransactionInterceptor (a commit is made) but this time not with the side effect of updating the modified entries to the DB.

            It's still not clear to me what does exactly cause the entries to be updated in case not all involved calls are marked as read only (as I experienced so far).

            - Peter

            Comment


            • #7
              hi dear
              i donot prefer to use <persistence-context/> if i will manage the persistence myself and i think that it is not intended for that,it is intended for long running transaction that span multiple views and commited at the end-state
              i prefer to use an openEntityManagerInViewInterceptor and map it to the required URLs
              i think that the problem is due to u persist using an entityManager other than the provided by the <persistence-context/> which the transaction bound to
              joe

              Comment


              • #8
                Thanks for your answer Joe.

                i donot prefer to use <persistence-context/> if i will manage the persistence myself and i think that it is not intended for that,it is intended for long running transaction that span multiple views and commited at the end-state
                Using <persistence-context> does not mean to me I do not control my transactional behavior, it's just a different way. As it looks now it enables me to modify data in a view state via ajax requests and to decide when the changes are committed database (and leaving the flow).

                Originally posted by fawzyj View Post
                i think that the problem is due to u persist using an entityManager other than the provided by the <persistence-context/> which the transaction bound to
                joe
                I can somehow remember that Keith has mentioned that in case I'm using Spring managed Dao's I should receive the PersistenceContext created by the flow element <persistence-context>.

                Anyway after reading some more I think I was faced with the normal behavior of find methods (they cause a flush) and I assume because my find methods were not annotated with readOnly=true a commit was executed.

                What would be different in case I would use openEntityManagerInViewInterceptor? Do you have some example code?

                - Peter

                Comment

                Working...
                X