|
From: Dave B. <dba...@on...> - 2005-05-20 17:18:20
|
Hi Juergen, Thanks for looking into this and providing an insightful description of the problem. For me, this mix of EJB CMT and Spring tx demarcation is only a temporary situation as I transition away from EJB. I've got a service methods that are called from both the web tier (need Spring to start a transaction) and from a SLSB (EJB CMT starts transaction). My problem now is that Spring 1.2's WebLogicJtaTransactionManager is not compatible with WebLogic 6.1 (org.springframework.transaction.TransactionSystemException: Could not initialize WebLogicJtaTransactionManager because WebLogic API classes are not available; nested exception is java.lang.ClassNotFoundException: weblogic.transaction.UserTransaction.). Do you think that your fix below is something that could be patched into 1.1.5? I'll do it, but I don't want to waste my time if you don't think that it is a good idea. Thanks, Dave Juergen Hoeller wrote: >Hi Dave, > >I've just verified that your scenario can indeed lead to broken cleanup: > >If the rollback gets triggered from some other thread (i.e. not the thread >that created the transaction), the Hibernate SessionHolder cannot get >removed from the original thread. That is actually already expected, as it >can also happen in case of remote transaction propagation: Spring will >simply remove the current Hibernate Session from the SessionHolder in this >case, and reuse the SessionHolder when another transaction gets executed on >that thread. > >However, the above only works with direct JTA Session synchronization only. >If Spring transaction synchronization is involved too (that is, if >transactions get initiated from either EJB CMT or Spring transaction >demarcation, not just from EJB CMT), an IllegalStateException will be thrown >whenever a thread with such an empty SessionHolder is supposed to execute a >Spring-driven transaction. This is straightforward to reproduce in a test >case. > >I've just fixed this issue for both Hibernate 2.1 and Hibernate3, to be >committed today. The fix should be available in the next nightly build, and >will be released in Spring 1.2.1. > >Note that it's generally recommended to use *either* EJB CMT *or* >Spring-driven transactions. Spring's Session synchronization for Hibernate >will work nicely with EJB CMT only, without any Spring transaction >demarcation involved. Mixing both is nevertheless valid, therefore the above >fix is necessary. > >Thanks for reporting this! > >Juergen > > >-----Original Message----- >From: spr...@li... >[mailto:spr...@li...]On Behalf >Of Dave Ballard >Sent: Wednesday, May 18, 2005 10:41 PM >To: spr...@li... >Subject: Re: [Springframework-developer] Race condition with transaction >synchronization? > > >Hello, > >Sorry to respond to my own post, but if there's someone out there that >is familiar with SessionFactoryUtils, I would appreciate a little of >your time to discuss this issue. This appears to be a bug in the JTA >session synchronization code for hibernate. > >Thanks, >Dave > >Dave Ballard wrote: > > > >>Hello, >> >>I posted this on the forums, but costin and Rod suggested that I post >>it here. >> >>I'm using Spring Framework 1.1.5 with Hibernate on WebLogic Server >>6.1. I'm testing timeout scenarios, and I've run into an issue I need >>some help with. I'm slowly eliminating EJB's from my application, but >>I do have some legacy EJB code to deal with. In my scenario, my >>servlet is calling a SLSB, which in turn calls spring-managed >>transactional services. These transaction service join the CMT >>transaction created by the EJB container. I have: >> >>Code: >> >>1) A servlet calls SLSB with CMT. >>2) The SLSB calls SessionFactoryUtils.getSession(sessionFactory, true) >>-- This binds the hibernate session to the current thread >>3) The SLSB calls a spring-managed transactional service >>-- This bean uses the bound session as expected >>4) The SLSB calls another spring-managed transactional service >>-- This bean uses the bound session as expected >>5) The SLSB exits >>-- The TransactionSynchronizationManager unbinds the bound session as >>expected >> >> >>So the non-timeout scenario functions as expected. Now I introduce a >>timeout (by causing blocking in by database) prior to (3). With the >>timeout scenario, I encounter one of two results: >> >>Code: >> >>A) A spring HibernateJdbcException wrapping a weblogic >>TimedOutException as expected. >>B) An IllegalStateException Already value >>[org.springframework.orm.hibernate.SessionHolder@6f2304] for key >>[net.sf.hibernate.impl.SessionFactoryImpl@655ad0] bound to thread >>[ExecuteThread: '29' for queue: 'default'] >> >> >>Whether I get (A) or (B) is seemingly random. I've created a >>diagnostic version of SessionFactoryUtils to see what is happening in >>more detail. >>In scenario (B), it looks like WebLogic's transaction manager is >>grabbing another thread from the pool and is invoking spring's >>JtaSessionSynchronization.afterCompletion() which is resulting in >>doClose() being called. I've added a dumpStack() in doClose(), and >>here is what I see. The line numbers will be a little off because of >>my diagnostic code: >> >>Code: >> >>java.lang.Exception: Stack trace >> at java.lang.Thread.dumpStack(Thread.java:992) >> at >> >> >> >org.springframework.orm.hibernate.SessionFactoryUtils.doClose(SessionFactory >Utils.java:738) > > >> at >> >> >> >org.springframework.orm.hibernate.SessionFactoryUtils.closeSessionOrRegister >DeferredClose(SessionFactoryUtils.java:726) > > >> at >> >> >> >org.springframework.orm.hibernate.SessionFactoryUtils.access$300(SessionFact >oryUtils.java:89) > > >> at >> >> >> >org.springframework.orm.hibernate.SessionFactoryUtils$SpringSessionSynchroni >zation.beforeCompletion(SessionFactoryUtils.java:867) > > >> at >> >> >> >org.springframework.orm.hibernate.SessionFactoryUtils$JtaSessionSynchronizat >ion.afterCompletion(SessionFactoryUtils.java:978) > > >> at >> >> >> >weblogic.transaction.internal.ServerSCInfo.callAfterCompletions(ServerSCInfo >.java:464) > > >> at >> >> >> >weblogic.transaction.internal.ServerTransactionImpl.callAfterCompletions(Ser >verTransactionImpl.java:2139) > > >> at >> >> >> >weblogic.transaction.internal.ServerTransactionImpl.setRolledBack(ServerTran >sactionImpl.java:2090) > > >> at >> >> >> >weblogic.transaction.internal.ServerTransactionImpl.globalRetryRollback(Serv >erTransactionImpl.java:2188)DEBUG > > >>18:19:23,000 [ExecuteThread: '34' for queue: 'default'] [edemo_acme] >>(Transacti >> at >> >> >> >weblogic.transaction.internal.ServerTransactionImpl.globalRollback(ServerTra >nsactionImpl.java:2080) > > >> at >> >> >> >weblogic.transaction.internal.TransactionImpl$1.execute(TransactionImpl.java >:1617) > > >> at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:159) >> at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:140) >> >> >>Meanwhile, the original timeout thread, who is in the middle of >>calling getSession(), and hasn't yet encountered the weblogic >>TimedOutException, >>tries to bind the session holder to the thread, and fails: >> >>Code: >> >>ERROR 18:19:23,046 [ExecuteThread: '34' for queue: 'default'] >>[edemo_acme] (TransactionAspectSupport.java:264) - Application >>exception overridden by rollback exception >>java.lang.IllegalStateException: Already value >>[org.springframework.orm.hibernate.SessionHolder@747db9] for key >>[net.sf.hibernate.impl.SessionFactoryImpl@606e55] bound to thread >>[ExecuteThread: '34' for queue: 'default'] >> at >> >> >> >org.springframework.transaction.support.TransactionSynchronizationManager.bi >ndResource(TransactionSynchronizationManager.java:147) > > >> at >> >> >> >org.springframework.orm.hibernate.SessionFactoryUtils.getSession(SessionFact >oryUtils.java:346) > > >> at >> >> >> >org.springframework.orm.hibernate.SessionFactoryUtils.getSession(SessionFact >oryUtils.java:266) > > >> at >> >> >> >org.springframework.orm.hibernate.SessionFactoryUtils.getSession(SessionFact >oryUtils.java:223) > > >> at >> >> >> >org.springframework.orm.hibernate.HibernateInterceptor.invoke(HibernateInter >ceptor.java:149) > > >> at >> >> >> >org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflect >iveMethodInvocation.java:144) > > >> at >> >> >> >org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopPro >xy.java:174) > > >> at $Proxy93.findContract(Unknown Source) >> at >>mycode.ContractServiceImpl.findContract(ContractServiceImpl.java:59) >> ... >> >> >>It's not clear to me who the culprit is here, not being that familiar >>with JTA and Spring. Perhaps the beforeCompletion() called by the >>weblogic transaction manager is not cleaning up properly? Any ideas? >> >>Thanks for your help, >>Dave >> >> >>------------------------------------------------------- >>This SF.Net email is sponsored by Oracle Space Sweepstakes >>Want to be the first software developer in space? >>Enter now for the Oracle Space Sweepstakes! >>http://ads.osdn.com/?ad_id=7412&alloc_id=16344&op=click >>_______________________________________________ >>Springframework-developer mailing list >>Spr...@li... >>https://lists.sourceforge.net/lists/listinfo/springframework-developer >> >> >> >> > > >------------------------------------------------------- >This SF.Net email is sponsored by Oracle Space Sweepstakes >Want to be the first software developer in space? >Enter now for the Oracle Space Sweepstakes! >http://ads.osdn.com/?ad_id=7412&alloc_id=16344&op=click >_______________________________________________ >Springframework-developer mailing list >Spr...@li... >https://lists.sourceforge.net/lists/listinfo/springframework-developer > > > >------------------------------------------------------- >This SF.Net email is sponsored by Oracle Space Sweepstakes >Want to be the first software developer in space? >Enter now for the Oracle Space Sweepstakes! >http://ads.osdn.com/?ad_id=7412&alloc_id=16344&op=click >_______________________________________________ >Springframework-developer mailing list >Spr...@li... >https://lists.sourceforge.net/lists/listinfo/springframework-developer > > > > |