View Full Version : One transaction per request w/Hibernate
ehauser
Aug 17th, 2004, 02:30 PM
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.
Martin Kersten
Aug 17th, 2004, 03:30 PM
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):
TransactionStatus transaction=getTransactionManager().
getTransaction(new DefaultTransactionDefinition());
To end the transaction:
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.
[quote]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... .
ehauser
Aug 17th, 2004, 05:06 PM
[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.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/flo/mentor</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFact oryBean">
<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.ehcache.hibernate.Provider</prop>
<prop key="hibernate.dialect">@hibernate.dialect@</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransac tionManager">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>
<bean id="meetingDAO" class="ai.flo.mentor.dao.impl.MeetingDAOHibernateImpl">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="meetingManager" class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean">
<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.MeetingManagerImpl">
<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.
irbouho
Aug 17th, 2004, 10:20 PM
This is the indeed behaviour!!!
Your transaction management configuration
<bean id="meetingManager" class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean">
<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.
irbouho
Aug 17th, 2004, 10:23 PM
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.ehcache.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?
ehauser
Aug 17th, 2004, 11:20 PM
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.
ehauser
Aug 17th, 2004, 11:32 PM
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.
Martin Kersten
Aug 18th, 2004, 12:51 AM
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:
TransactionStatus transaction=getTransactionManager().
getTransaction(new DefaultTransactionDefinition());
End a transaction:
getTransactionManager().commit(transaction);
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.
Colin Sampaleanu
Aug 18th, 2004, 03:07 PM
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,
irbouho
Aug 18th, 2004, 03:17 PM
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.
ehauser
Aug 18th, 2004, 03:37 PM
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.
Jari
Aug 19th, 2004, 12:03 PM
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).
garpinc2
Nov 1st, 2004, 06:23 PM
I'm having same issue. Any resolution on this?
ehauser
Nov 1st, 2004, 06:46 PM
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.Transa ctionProxyFactoryBean">
<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.TransactionInterceptor" />
Then, I use the following for all of my DAO managers:
<bean id="mentorManager" class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean">
<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/
garpinc2
Nov 2nd, 2004, 08:57 PM
Can't find that class. Please advise. ii.webwork.interceptor.TransactionInterceptor
Also any ideas about how I could adapt this for Struts
ehauser
Nov 2nd, 2004, 09:43 PM
Can't find that class. Please advise. ii.webwork.interceptor.TransactionInterceptor
Also any ideas about how I could adapt this for Struts
That class is specific to my individual project. It doesn't really apply to Struts because interceptors do not exist in the Struts framework. There is a sample chapter for Spring Live which discusses Spring integration with Struts. I'm assuming that there is a probably a method in the Spring controller for Struts that you could use for transaction demarcation, and achieve the similar affect.
garpinc2
Nov 2nd, 2004, 09:47 PM
A little while ago we created ServletWrappingController which supports Spring interceptors for Struts. Maybe posting the code here would help me out.
garpinc2
Nov 3rd, 2004, 05:11 PM
I'm still waiting on your posting...
Thanks,
Garry
Powered by vBulletin® Version 4.2.1 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.