|
From: Juergen H. <ju...@in...> - 2005-05-22 10:13:05
|
Dave, I've already finished the reworking: AbstractPlatformTransactionManager discriminated between a "local" and a "global" rollback-only flag now, which was fortunately straightforward to do. "local" refers to a TransactionStatus.setRollbackOnly() call by the application, which leads to a silent rollback (usually, the application will throw an appropriate exception). "global" refers to the UserTransaction or resource holder being marked as rollback-only, which can only happen through the transaction coordinator. One example for this is a transaction timeout. There is one side effect, though: If you have an outer and an inner transaction and call TransactionStatus.setRollbackOnly() on the inner transaction without throwing an exception, you got a silent rollback of the outer transaction before. Now, the outer transaction will throw an UnexpectedRollbackException instead. I guess it's more appropriate to throw an UnexpectedRollbackException here in any case, to avoid surprises for callers of the outer transaction. Usually, the inner transaction will throw an exception anyway, so the outer transaction will simply rollback and propagate that exception. In total, I'm happy with the new semantics. Rollbacks will always lead to an exception, unless the local TransactionStatus object received a setRollbackOnly() call from the application. The slight change in semantics should not be an issue, as I do not expect any application to rely on such silent rollbacks of outer transactions. I'll commit this today; it should be available in the next nightly build. Please give this refined behavior a try and let me know how it works for you! Juergen -----Original Message----- From: spr...@li... [mailto:spr...@li...]On Behalf Of Dave Ballard Sent: Sunday, May 22, 2005 1:22 AM To: spr...@li... Subject: Re: [Springframework-developer] Spring 1.2 Spring JTA tx timeout, tx rolls back, but no exception thrown (another race condition) Hi Juergen, Thanks for checking into this. Does look a little ugly. Hopefully you'll find a way to tell the difference between the two different rollback situations (or to inquire if in fact a timeout has occurred). Currently this is a show-stopper for me. Although this type of timeout won't happen frequently, it will happen, and the consequences will be a little difficult to track down because of the lack of an exception. Thanks again for your help, Dave Juergen Hoeller wrote: >Good point - thanks for reporting this! JTA implementations seem to mark >transaction as rollback-only when they have timed out, without further >indication. So unless you attempt an actual resource operation after the >timeout, there is no guarantee than an exception gets thrown before commit. > >If Spring discovers a rollback-only status, it assumes that the application >has set the transaction to rollback-only and triggers a silent rollback. >This will usually happen when TransactionStatus.setRollbackOnly() has been >called, instead of configuring a rollback rule, with an application-level >exception getting thrown. > >In the case of a JTA timeout, the rollback-only marker comes from the JTA >subsystem, though. Spring effectively misinterprets that marker as driven by >the application, which leads to an inappropriate silent reaction. I'll fix >that for Spring 1.2.1, although it's unfortunately not that trivial for the >general case. > >Juergen > > >-----Original Message----- >From: spr...@li... >[mailto:spr...@li...]On Behalf >Of Dave Ballard >Sent: Friday, May 20, 2005 10:44 PM >To: spr...@li... >Subject: [Springframework-developer] Spring 1.2 Spring JTA tx timeout, >tx rolls back, but no exception thrown (another race condition) > > >Hi Juergen, > >Using unpatched Spring 1.2 on WebLogic 6.1. I've defined a >Spring-managed service bean, with the following transaction manager and >transaction interceptor beans: > > <bean id="MyTransactionManager" >class="org.springframework.transaction.jta.JtaTransactionManager"> > <property >name="transactionManagerName"><value>java:comp/UserTransaction</value></pro p >erty> > </bean> > > <bean id="MyTransactionInterceptor" >class="org.springframework.transaction.interceptor.TransactionInterceptor"> > <property name="transactionManager"><ref >bean="MyTransactionManager"/></property> > <property name="transactionAttributeSource"> > <value> > PaymentService.commit=PROPAGATION_REQUIRED,-Exception > </value> > </property> > </bean> > >The transactional demarcation causes a commit when the method succeeds, >and causes a rollback when an exception is thrown (and throws the >exception), as expected. However, if I introduce a 40 second sleep in >the method, the transaction rolls back as expected, but sometimes no >exception is thrown. In the case where no exception is thrown, I can see >in the Spring log: > > WARN 14:45:03,156 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (EjbUtils.java:626) - START SLEEP 40: >PaymentServiceImpl.commit() 40 seconds...... > WARN 14:45:43,156 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (EjbUtils.java:633) - DONE SLEEP 40: >PaymentServiceImpl.commit() 40 seconds...... >DEBUG 14:45:43,156 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (TransactionAspectSupport.java:258) - Invoking commit for >transaction on PaymentService.commit >DEBUG 14:45:43,156 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (AbstractPlatformTransactionManager.java:382) - >Transactional code has requested rollback >DEBUG 14:45:43,156 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (AbstractPlatformTransactionManager.java:542) - Triggering >beforeCompletion synchronization >DEBUG 14:45:43,156 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (TransactionSynchronizationManager.java:177) - Removed >value [org.springframework.orm.hibernate.SessionHolder@57f820] for key >[net.sf.hibernate.impl.SessionFactoryImpl@39569e] from thread >[ExecuteThread: '30' for queue: 'default'] >DEBUG 14:45:43,156 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (SessionFactoryUtils.java:730) - Closing Hibernate Session >DEBUG 14:45:43,156 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (AbstractPlatformTransactionManager.java:463) - Initiating >transaction rollback >DEBUG 14:45:43,156 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (JtaTransactionManager.java:719) - Rolling back JTA transaction >DEBUG 14:45:43,156 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (AbstractPlatformTransactionManager.java:572) - Triggering >afterCompletion synchronization >DEBUG 14:45:43,156 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (TransactionSynchronizationManager.java:252) - Clearing >transaction synchronization > INFO 14:45:43,171 [ExecuteThread: '30' for queue: 'default'] >[edemo_acme] (PaymentCommit.java:167) - PERFORMANCE END PaymentCommit > >This is an intermittent problem that occurs in both 1.1.5 and 1.2. I run >the same test over and over, and while it always rolls back, it only >sometimes throws an exception. In the case where it does throw an >exception, the log is different: > > WARN 15:18:54,109 [ExecuteThread: '31' for queue: 'default'] >[edemo_acme] (EjbUtils.java:626) - START SLEEP 40: >PaymentServiceImpl.commit() 40 seconds...... > WARN 15:19:34,109 [ExecuteThread: '31' for queue: 'default'] >[edemo_acme] (EjbUtils.java:633) - DONE SLEEP 40: >PaymentServiceImpl.commit() 40 seconds...... >DEBUG 15:19:34,109 [ExecuteThread: '31' for queue: 'default'] >[edemo_acme] (TransactionAspectSupport.java:241) - Invoking commit for >transaction on method 'commit' in class [PaymentService] >DEBUG 15:19:34,109 [ExecuteThread: '31' for queue: 'default'] >[edemo_acme] (AbstractPlatformTransactionManager.java:523) - Triggering >beforeCommit synchronization >DEBUG 15:19:34,109 [ExecuteThread: '31' for queue: 'default'] >[edemo_acme] (SessionFactoryUtils.java:809) - Flushing Hibernate session >on transaction synchronization >DEBUG 15:19:34,109 [ExecuteThread: '31' for queue: 'default'] >[edemo_acme] (SQLErrorCodeSQLExceptionTranslator.java:225) - Unable to >translate SQLException with errorCode '0', will now try the fallback >translator >DEBUG 15:19:34,109 [ExecuteThread: '31' for queue: 'default'] >[edemo_acme] (SQLStateSQLExceptionTranslator.java:74) - Translating >SQLException with SQLState 'null' and errorCode '0' and message [The >transaction is no longer active (status = Rolled back. >[Reason=weblogic.transaction.internal.TimedOutException: Transaction >timed out after 28 seconds >[snip] > >This appears to be another race condition. In the case where the >exception is thrown, the transaction has not yet been flagged as >rollback-only. The code proceeds to attempt a hibernate flush(), and >this causes a SQLException(TimedOutException) to be thrown. > >In the first case where no exception is thrown, the transaction has >already been flagged rollback-only, so the code never calls hibernate >flush, and simply returns w/o an exception after rolling back the tx. > >This is a pretty serious problem for my application because the calling >code has no idea that the transaction rolled back. > >Thanks, >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 |