Announcement Announcement Module
Collapse
No announcement yet.
One transaction per request w/Hibernate Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • One transaction per request w/Hibernate

    I'm currently using the TransactionProxyFactoryBean to handle transaction using Hibernate in my application. After viewing the logging, I noticed that a new transaction seems to be started/closed for every call made to the session. I would like to have it so that the transaction lasts for the entire processing of a single request (really the entire life of the ThreadLocal for the Session). Is there an easy way to accomplish this? Thanks.

  • #2
    [quote]I'm currently using the TransactionProxyFactoryBean to handle transaction using Hibernate in my application.After viewing the logging, I noticed that a new transaction seems to be started/closed for every call made to the session.[quote]

    Please post your session factory, datasource, transaction manager and all other related bean configurations+ an example method.

    I guess you missconfigured the hibernate transaction manager some how. It looks like an unnormal behaviour.

    Since you asked, here is a little Transaction snippet to get you started on managing transactions explicitly.

    Begin a transaction (start a new one if none exist):
    Code:
    TransactionStatus transaction=getTransactionManager().
            					getTransaction(new DefaultTransactionDefinition());
    To end the transaction:
    Code:
    getTransactionManager().commit(transaction);
    Note: The transaction is rolled back even when commiting if the rollback flag is set of the TransactionStatus object.


    For testing you may also surround your code by an explicit transaction using the above call. If there are still a lot of transactions started than you have a missconfiguration.

    Another issue is wether the reported transactions are real transations or just nested ones. You know nested transactions maybe are logged, too but they do not issus a real transaction. So please provide your log files as well.

    Is there an easy way to accomplish this?
    See the above code snippet. It's quite simple and easy to use. Beside the declarative transaction specification using AOP should also work... .

    Comment


    • #3
      [Please post your session factory, datasource, transaction manager and all other related bean configurations+ an example method.]

      Ok. Here goes:

      <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryB ean">
      <property name="jndiName">
      <value>java:comp/env/jdbc/flo/mentor</value>
      </property>
      </bean>

      <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSess ionFactoryBean">
      <property name="dataSource"><ref local="dataSource"/></property>
      <property name="mappingResources">
      <list>
      <value>ai/flo/mentor/model/Address.hbm.xml</value>
      <value>ai/flo/mentor/model/Meeting.hbm.xml</value>
      <value>ai/flo/mentor/model/Person.hbm.xml</value>
      <value>ai/flo/mentor/model/PhoneNumber.hbm.xml</value>
      <value>ai/flo/mentor/model/School.hbm.xml</value>
      </list>
      </property>
      <property name="hibernateProperties">
      <props>
      <prop key="connection.datasource">java:comp/env/jdbc/flo/mentor</prop>
      <prop key="hibernate.cache.provider_cache">net.sf.ehcach e.hibernate.Provider</prop>
      <prop key="hibernate.dialect">@hibernate.dialect@</prop>
      </props>
      </property>
      </bean>

      <bean id="transactionManager" class="org.springframework.orm.hibernate.Hibernate TransactionManager">
      <property name="sessionFactory"><ref bean="sessionFactory"/></property>
      </bean>

      <bean id="meetingDAO" class="ai.flo.mentor.dao.impl.MeetingDAOHibernateI mpl">
      <property name="sessionFactory">
      <ref local="sessionFactory" />
      </property>
      </bean>

      <bean id="meetingManager" class="org.springframework.transaction.interceptor .TransactionProxyFactoryBean">
      <property name="transactionManager">
      <ref local="transactionManager" />
      </property>
      <property name="target">
      <ref local="meetingManagerTarget" />
      </property>
      <property name="transactionAttributes">
      <props>
      <prop key="*">PROPAGATION_REQUIRED</prop>
      </props>
      </property>
      </bean>

      <bean id="meetingManagerTarget" class="ai.flo.mentor.manager.impl.MeetingManagerIm pl">
      <property name="meetingDAO">
      <ref local="meetingDAO" />
      </property>
      </bean>

      I'm using the xwork-spring project to inject these beans into my Xwork actions and running a sample method on them which is using Hibernate. All of that seems work fine. I included some cuts of the debug log below. If you follow along, you can see that Spring creates a new transaction for the load method and a new transaction for the save method (which also opens and closes the Session each time). What I want to be able to do is use a single Session for each request. That way I only have one Session (and Transaction) for all of my processing.

      I may also just not know how to do this, but the only reason I'm using the transaction is because I want the session to automatically flush every time. I saw the method on HibernateAccessor where you could set the flush mode to auto, but I didn't see anywhere you could configure that.

      17:00:08,242 DEBUG TransactionInterceptor:196 - Getting transaction for method 'load' in class [ai.flo.mentor.manager.StudentManager]
      17:00:08,244 DEBUG HibernateTransactionManager:196 - Using transaction object [org.springframework.orm.hibernate.HibernateTransac tionObject@19e6baa]
      17:00:08,256 DEBUG HibernateTransactionManager:268 - Creating new transaction
      17:00:08,258 DEBUG SessionFactoryUtils:307 - Opening Hibernate session
      17:00:08,259 DEBUG SessionImpl:555 - opened session
      17:00:08,260 DEBUG HibernateTransactionManager:290 - Opened new session [net.sf.hibernate.impl.SessionImpl@1ae90c9] for Hibernate transaction
      17:00:08,261 DEBUG JDBCTransaction:37 - begin
      17:00:08,262 DEBUG JDBCTransaction:41 - current autocommit status:true
      17:00:08,263 DEBUG JDBCTransaction:43 - disabling autocommit
      17:00:08,269 DEBUG HibernateTransactionManager:332 - Exposing Hibernate transaction as JDBC transaction [UserConnectionAdapter[com.caucho.sql.XAConnectionAdapter@1fe96f2]]
      <-- snip -->
      17:00:08,626 DEBUG SessionImpl:2359 - executing flush
      17:00:08,627 DEBUG SessionImpl:2824 - post flush
      17:00:08,633 DEBUG SessionImpl:585 - transaction completion
      17:00:08,634 DEBUG JDBCTransaction:103 - re-enabling autocommit
      17:00:08,644 DEBUG HibernateTransactionManager:543 - Triggering afterCompletion
      synchronization
      17:00:08,647 DEBUG TransactionSynchronizationManager:232 - Clearing transaction
      synchronization
      17:00:08,649 DEBUG TransactionSynchronizationManager:163 - Removed value [org.springframework.orm.hibernate.SessionHolder@15 44942] for key [net.sf.hibernate.impl.SessionFactoryImpl@16d4a3e] from thread [tcpConnection-8080-1]
      17:00:08,653 DEBUG TransactionSynchronizationManager:163 - Removed value [org.springframework.jdbc.datasource.ConnectionHold er@1a39fdc] for key [[DBPool jdbc/flo/mentor]] from thread [tcpConnection-8080-1]
      17:00:08,654 DEBUG HibernateTransactionManager:458 - Closing Hibernate session [net.sf.hibernate.impl.SessionImpl@1ae90c9] after transaction
      17:00:08,655 DEBUG SessionFactoryUtils:533 - Closing Hibernate session
      17:00:08,656 DEBUG SessionImpl:573 - closing session
      17:00:08,658 DEBUG SessionImpl:3336 - disconnecting session
      17:00:08,659 DEBUG SessionImpl:585 - transaction completion
      17:00:08,660 DEBUG TransactionInterceptor:196 - Getting transaction for method 'save' in class [ai.flo.mentor.manager.MentorManager]
      17:00:08,661 DEBUG HibernateTransactionManager:196 - Using transaction object [org.springframework.orm.hibernate.HibernateTransac tionObject@1bff971]
      17:00:08,662 DEBUG HibernateTransactionManager:268 - Creating new transaction
      17:00:08,663 DEBUG SessionFactoryUtils:307 - Opening Hibernate session
      17:00:08,685 DEBUG SessionImpl:555 - opened session
      17:00:08,686 DEBUG HibernateTransactionManager:290 - Opened new session [net.sf.hibernate.impl.SessionImpl@91a829] for Hibernate transaction
      17:00:08,687 DEBUG JDBCTransaction:37 - begin
      17:00:08,688 DEBUG JDBCTransaction:41 - current autocommit status:true
      17:00:08,689 DEBUG JDBCTransaction:43 - disabling autocommit
      17:00:08,696 DEBUG HibernateTransactionManager:332 - Exposing Hibernate transaction as JDBC transaction [UserConnectionAdapter[com.caucho.sql.XAConnectionAdapter@1fe96f2]]
      <-- snip -->
      17:00:09,609 DEBUG BatcherImpl:269 - closing statement
      17:00:09,610 DEBUG SessionImpl:2824 - post flush
      17:00:09,617 DEBUG SessionImpl:585 - transaction completion
      17:00:09,619 DEBUG JDBCTransaction:103 - re-enabling autocommit
      17:00:09,624 DEBUG HibernateTransactionManager:543 - Triggering afterCompletion
      synchronization
      17:00:09,635 DEBUG TransactionSynchronizationManager:232 - Clearing transaction
      synchronization
      17:00:09,636 DEBUG TransactionSynchronizationManager:163 - Removed value [org.springframework.orm.hibernate.SessionHolder@11 80cbd] for key [net.sf.hibernate.impl.SessionFactoryImpl@16d4a3e] from thread [tcpConnection-8080-1]
      17:00:09,637 DEBUG TransactionSynchronizationManager:163 - Removed value [org.springframework.jdbc.datasource.ConnectionHold er@b73194] for key [[DBPool jdbc/flo/mentor]] from thread [tcpConnection-8080-1]
      17:00:09,638 DEBUG HibernateTransactionManager:458 - Closing Hibernate session [net.sf.hibernate.impl.SessionImpl@91a829] after transaction
      17:00:09,639 DEBUG SessionFactoryUtils:533 - Closing Hibernate session
      17:00:09,640 DEBUG SessionImpl:573 - closing session
      17:00:09,641 DEBUG SessionImpl:3336 - disconnecting session
      17:00:09,646 DEBUG SessionImpl:585 - transaction completion

      Thanks.

      Comment


      • #4
        This is the indeed behaviour!!!
        Your transaction management configuration
        Code:
        <bean id="meetingManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
          <property name="transactionManager"> 
            <ref local="transactionManager" /> 
          </property> 
          <property name="target"> 
            <ref local="meetingManagerTarget" /> 
          </property> 
          <property name="transactionAttributes"> 
            <props> 
              <prop key="*">PROPAGATION_REQUIRED</prop> 
            </props> 
          </property> 
        </bean>
        means Spring will either create a new transaction for each method call or reuse an existing transaction (if a transaction can be found). After the method returns, Spring closes the transaction if necessary (only new transaction will be closed).
        17:00:08,242 DEBUG TransactionInterceptor:196 - Getting transaction for method 'load' in class [ai.flo.mentor.manager.StudentManager]

        17:00:08,660 DEBUG TransactionInterceptor:196 - Getting transaction for method 'save' in class [ai.flo.mentor.manager.MentorManager]
        Spring created a new transaction for StudentManager.load, invoked the load method and then closed the transaction. The same thing was done for MentorManager.save.

        Now, if you want to span multiple methods (o1.m1, o2.m2, o3.m3) call into the same transaction, you need to declare a new method that calls o1.m1, o2.m2 and o3.m3, and configure transaction management for this new method.

        Comment


        • #5
          just wondering!!!
          <property name="dataSource"><ref local="dataSource"/></property>
          ...
          <prop key="connection.datasource">java:comp/env/jdbc/flo/mentor</prop>
          aren't you defining the datasource twice here?
          <prop key="hibernate.cache.provider_cache">net.sf.ehcach e.hibernate.Provider</prop>
          which second level cache (cache provider) are you using?
          <prop key="hibernate.dialect">@hibernate.dialect@</prop>
          do you process your file before loading it by Spring?

          Comment


          • #6
            aren't you defining the datasource twice here?
            Actually, yes =). That code got cut and paste from my hibenate.cfg.xml. Thanks for pointing that out.

            which second level cache (cache provider) are you using?
            Ehcache. http://www.hibernate.org/158.html

            do you process your file before loading it by Spring?
            That's an Ant filter. I use HSQL for my unit tests and another database in production.

            Comment


            • #7
              Now, if you want to span multiple methods (o1.m1, o2.m2, o3.m3) call into the same transaction, you need to declare a new method that calls o1.m1, o2.m2 and o3.m3, and configure transaction management for this new method.
              Ok. That makes a little more sense. I don't want create a transaction for every method call. I was looking at the Javadoc and thought that was the behavior of PROPAGATION_REQUIRED.

              What I would really like to do is have a transaction start at the beginning of every request and end when the request processing is done. It seems that could be done programmatically though a filter, but I wasn't sure if there was another way. That way I don't have to chain the methods togther to specify the transaction. The application is pretty simple, so I just need the transaction to rollback for any uncaught exception. I also want to make sure that the Session flushes at the end.

              Comment


              • #8
                What I would really like to do is have a transaction start at the beginning of every request and end when the request processing is done. It seems that could be done programmatically though a filter, but I wasn't sure if there was another way. That way I don't have to chain the methods togther to specify the transaction. The application is pretty simple, so I just need the transaction to rollback for any uncaught exception. I also want to make sure that the Session flushes at the end.
                I usally stick to programmatical transaction management. It is quite easy to do within spring. :

                Begin a transaction:
                Code:
                TransactionStatus transaction=getTransactionManager&#40;&#41;.
                        					getTransaction&#40;new DefaultTransactionDefinition&#40;&#41;&#41;;
                End a transaction:
                Code:
                getTransactionManager&#40;&#41;.commit&#40;transaction&#41;;
                My unit tests are initially spanning a transaction around the whole test code. Only when a method squenece requires it's own transaction management, i just commit the 'surrounding' transaction before the sequence start. It's quite easy.

                Comment


                • #9
                  For most use cases people should prefer to use declarative transaction management. It results in less code, and less of a dependency on Spring...

                  Regards,

                  Comment


                  • #10
                    I found using declarative transaction management very flexible since it is very easy to change / scale-up / scale-down your transaction strategy without having to edit your java source.

                    Comment


                    • #11
                      I actually found a good pattern to use for what I wanted to do. Since, I'm using Webwork it was pretty easy to have a transaction start and close and the beginning and ending of the processing of each of my action invocations.

                      Comment


                      • #12
                        Originally posted by ehauser
                        I actually found a good pattern to use for what I wanted to do. Since, I'm using Webwork it was pretty easy to have a transaction start and close and the beginning and ending of the processing of each of my action invocations.
                        I've been using WebWork 2 and Spring in conjunction in a project that started in December 2003. At that time nobody had published a really compelling and simple integration between the two, so I made a home-grown solution that basically replaced WebWork's action factory with a simple factory that basically just autowires the WW actions via their constructors (PicoContainer -style). It's worked very well.

                        In my project, I also considered WebWork actions to be natural units-of-work (like adding a user, creating a news article etc), so I made my transaction handling work so that each action invocation occured in a single transaction.

                        My actions interact with different services and domain objects and all db access calls are executed in the same tx context. Spring works great for stuff like this (already back then, and 'tis maturing all the time).

                        Comment


                        • #13
                          I'm having same issue. Any resolution on this?

                          I'm having same issue. Any resolution on this?

                          Comment


                          • #14
                            Re: I'm having same issue. Any resolution on this?

                            Originally posted by garpinc2
                            I'm having same issue. Any resolution on this?
                            I eventually found a solution that works pretty well for me. I have an interceptor in Webwork's stack that doesn't do anything, but it allows for every action to execute under a single transaction.

                            <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor .TransactionProxyFactoryBean">
                            <property name="transactionManager">
                            <ref local="transactionManager" />
                            </property>
                            <property name="target">
                            <ref local="transactionInterceptorTarget" />
                            </property>
                            <property name="transactionAttributes">
                            <props>
                            <prop key="intercept">PROPAGATION_REQUIRED</prop>
                            </props>
                            </property>
                            </bean>

                            <bean id="transactionInterceptorTarget" class="ii.webwork.interceptor.TransactionIntercept or" />

                            Then, I use the following for all of my DAO managers:

                            <bean id="mentorManager" class="org.springframework.transaction.interceptor .TransactionProxyFactoryBean">
                            <property name="transactionManager">
                            <ref local="transactionManager" />
                            </property>
                            <property name="target">
                            <ref local="mentorManagerTarget" />
                            </property>
                            <property name="transactionAttributes">
                            <props>
                            <prop key="*">PROPAGATION_MANDATORY</prop>
                            </props>
                            </property>
                            </bean>

                            This works like a charm. I'm using the xwork-spring integration library. It's available at https://xwork-optional.dev.java.net/

                            Comment


                            • #15
                              Can't find that class. Please advise.

                              Can't find that class. Please advise. ii.webwork.interceptor.TransactionInterceptor

                              Also any ideas about how I could adapt this for Struts

                              Comment

                              Working...
                              X