Page 1 of 2 12 LastLast
Results 1 to 10 of 18

Thread: One transaction per request w/Hibernate

  1. #1

    Default 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. #2
    Join Date
    Aug 2004
    Location
    Germany, Magdeburg
    Posts
    279

    Default

    [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... .

  3. #3

    Default

    [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.

  4. #4
    Join Date
    Aug 2004
    Location
    Montréal, Canada
    Posts
    845

    Default

    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.
    Omar Irbouh

    Spring Modules Team
    http://irbouh.blogspot.com/

  5. #5
    Join Date
    Aug 2004
    Location
    Montréal, Canada
    Posts
    845

    Default

    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?
    Omar Irbouh

    Spring Modules Team
    http://irbouh.blogspot.com/

  6. #6

    Default

    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.

  7. #7

    Default

    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.

  8. #8
    Join Date
    Aug 2004
    Location
    Germany, Magdeburg
    Posts
    279

    Default

    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.

  9. #9
    Join Date
    Aug 2004
    Location
    Toronto, Canada
    Posts
    736

    Default

    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,
    Colin Sampaleanu
    SpringSource - http://www.springsource.com

  10. #10
    Join Date
    Aug 2004
    Location
    Montréal, Canada
    Posts
    845

    Default

    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.
    Omar Irbouh

    Spring Modules Team
    http://irbouh.blogspot.com/

Similar Threads

  1. Replies: 9
    Last Post: Nov 1st, 2005, 10:36 PM
  2. Unit testing with JOTM and JtaTransactionManager
    By lalle in forum Architecture
    Replies: 1
    Last Post: Oct 15th, 2005, 09:05 AM
  3. Replies: 3
    Last Post: May 16th, 2005, 07:04 AM
  4. Replies: 3
    Last Post: Nov 19th, 2004, 07:16 PM
  5. Transaction pb Hibernate/MySQL
    By syluser in forum Data
    Replies: 2
    Last Post: Aug 28th, 2004, 02:40 PM

Posting Permissions

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