Announcement Announcement Module
Collapse
No announcement yet.
Prog. rollback of decl. transaction without interceptor - pb Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Prog. rollback of decl. transaction without interceptor - pb

    I’m having problems triggering transaction rollback programmatically within a declaratively managed transaction.

    Some methods on our business interface have a 'preview' boolean parameter. If the argument is true, the method should complete successfully (generating a summary of what was done), but no changes should be made to the database - i.e. we want rollback without having to throw an exception.

    I have tried two techniques, one writing an interceptor implementing MethodBeforeAdvice, passed to TransactionProxyFactoryBean with its preInterceptors property. The interceptor checks whether the last method parameter is a boolean of value true, if so it obtains the TransactionStatus from the transactionManager (passed to the interceptor as a property), and calls setRollbackOnly():

    Code:
    if (transactionManager == null)
    {
        throw new IllegalStateException("transactionManager property not set -check application context is correctly configured.");
    }
    
    TransactionStatus status = transactionManager.getTransaction(null);                                    
    status.setRollbackOnly();
    This works correctly, however only a few methods have the preview parameter and I would rather not bother with an interceptor at all and just call setRollbackOnly() from the business logic itself if preview is set to true, once again passing the transactionManager as a property to my implementation class.

    For some reason the later approach doesn’t work.

    The transaction is not rolling back even though I am executing exactly the same setRollbackOnly() code within the business logic that I am in the interceptor.

    My application context is as follows:

    Code:
    <bean id="hibernateSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="mappingResources">
            <list><value>location.hbm.xml</value></list>
        </property>
    
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">
                    org.hibernate.dialect.SQLServerDialect
                </prop>
                <prop key="hibernate.show_sql">false</prop>
            </props>
        </property>
    		
        <property name="dataSource">
            <ref bean="dataSource"/>
        </property>			
    </bean>
    
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref bean="hibernateSessionFactory"/>
        </property>
    </bean>	
    
    <bean id="locationManagerPreviewInterceptor" class="com.abc.location.domain.LocationManagerPreviewInterceptor">
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>
    </bean>
      
    <bean id="locationManagerDao" class="com.abc.location.dao.LocationManagerDao">
        <property name="sessionFactory">
            <ref bean="hibernateSessionFactory"/>
        </property>
    </bean>
    
    <bean id="locationManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>
        <!-- With the following pre-interceptor, the transaction is correctly rolled back. If I comment out this property, and have the application code call setRollbackOnly&#40;&#41; on TransactionStatus itself, the transaction doesn't roll back -->	
        <property name="preInterceptors">
            <list>
                <ref bean="locationManagerPreviewInterceptor"/>
            </list>
        </property>    
        <property name="target">
            <ref bean="locationManagerImpl"/>
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="*">PROPAGATION_REQUIRED,-Throwable</prop>
            </props>
        </property>
    </bean>
    
    <bean id="locationManagerImpl" class="com.abc.location.domain.LocationManagerImpl">
        <property name="locationManagerDao">
            <ref bean="locationManagerDao"/>
        </property>
        <!-- Give the business interface implementation a reference to the transaction manager so it can rollback the transaction programmatically. -->
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>		
    </bean>
    What am I doing wrong here? I'm passing the same reference to the transactionManager singleton to both my interceptor and business logic class. I get the same behaviour in my standalone functional tests outside of a container and deployed under JBoss 4.0.1. I'm using Spring 1.2.4.

    Thanks in advance for your help.

  • #2
    You can use the static TransactionAspectSupport.currentTransactionStatus( ) method to obtain the correct TransactionStatus for flagging the transaction for rollback.

    Hope that helps,
    Andreas

    Comment


    • #3
      Fixed. Thanks Andreas.

      Thanks Andreas. That's working fine now, and simpler than passing transactionManager as a property.

      Comment

      Working...
      X