Results 1 to 2 of 2

Thread: Confused about Transaction Proxying

  1. #1
    Join Date
    Apr 2006
    Posts
    1

    Default Confused about Transaction Proxying

    I am a newbie and have been trying for 3 days to get my hands around the type of jdbc transaction support that is available through Spring. Despite all my reading, researching, and testing, I'm still unclear on a few issues I hope you can help me resolve.

    I am using Spring JDBC ... JDBCTemplate calls from within a Dao/DaoImpl Spring-Managed Bean. The Dao/DaoImpl Spring-Managed Bean is called from a Service/ServiceImpl Spring-Managed Bean. The Service/ServiceImpl Spring-Managed Bean is called from a Non-Spring Managed object, which uses a BeanFactory to get a reference.

    NotManaged
    --> ManagedService
    --> ManagedDao
    --> JDBCTemplate

    I am using Commons Attributes to denote transaction demarkation since we are using JDK 1.4 and I don't want my developers to have to modify the spring-config.xml for every transaction they want (and we don't want to use automatic wiring/name matching/etc.). Here's the configuration:

    Code:
    <!-- Begin: Transaction Using Jakarta Commons Metadata and AOP to denote Transactions -->
    <bean id="metadataAttributes"
        class="org.springframework.metadata.commons.CommonsAttributes">
    </bean>
      
    <bean id="transactionAttributeSource"
        class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource">
        <property name="attributes">
            <ref bean="metadataAttributes"/>
        </property>
    </bean>
    
    <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
       <property name="transactionManager">
          <ref bean="xuiTransactionManager"/>
       </property>
       <property name="transactionAttributeSource">
          <ref bean="transactionAttributeSource" />
       </property>
    </bean>
      
    <bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
        <property name="transactionInterceptor">
            <ref bean="transactionInterceptor"/>
        </property>
    </bean>
    
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
    Through much debugging and reading I discovered the following:

    NotManaged
    --> ManagedService.transactionalMethod1()
    works just fine

    NotManaged
    --> ManagedService.nonTransactionalMethod()
    --> ManagedService.transactionalMethod2()
    does NOT provide transaction support due to the fact that the proxy is not being used when a method within a Spring-Managed bean calls another method within a Spring-Managed bean ... even if the endpoint method is marked as transactional. Note that ManagedService.nonTransactionalMethod() iterates over a collection and calls ManagedService.transactionalMethod2() for each object ... and I want to commit or rollback on each object, not on the collection as a whole.

    So, I decided that my only (unfortunate) option was to refactor ManagedService.transactionalMethod2() into ManagedServiceHelper.transactionalMethod2(). I setup ManagedServiceHelper as a Spring-Managed Bean in the spring-config.xml, setup ManagedService to have an instance of ManagedServiceHelper provided to it by Dependency Injection, and then do the following:

    NotManaged
    --> ManagedService.nonTransactionalMethod()
    --> ManagedServiceHelper.transactionalMethod2()

    To my surprise (and disgust), I am still only getting a Proxy between NotManaged and ManagedService.nonTransactionalMethod(). I am not getting a Proxy (or a transaction) between ManagedService.nonTransactionalMethod() and ManagedServiceHelper.transactionalMethod2().

    I do have transactional support working between NotManaged --> ManagedService.transactionalMethod1() so I do not feel that this is a problem with my setup, but I have pasted below some code anyhow.

    NotManaged
    Code:
    managedService = (ManagedService)getSpringContext().getBean("ManagedService", ManagedService.class);
    // The call below results in a proper transaction
    int result1 = managedService.transactionalMethod1();
    // The call below does not have a transaction anywhere in the successive callstack
    int result2 = managedService.nonTransactionalMethod1();
    ManagedService
    Code:
    /** Created using Dependency Injection */
    ManagedServiceHelper managedServiceHelper=null;
    public void setManagedServiceHelper(ManagedServiceHelper msh) {
      this.managedServiceHelper = msh;
    }
    
    /**
     * NOTE: Transaction works properly when called from NotManaged
     * @@RuleBasedTransactionAttribute(propagationBehaviorName="PROPAGATION_REQUIRED", isolationLevelName="ISOLATION_READ_COMMITTED")
     * @@RollbackRuleAttribute(Throwable.class)
     */
    public int transactionalMethod1() {
    .
    .
    .
    }
    
    /**
     * No Transaction Demarkation
     */
    public int nonTransactionalMethod() {
      while (iter.hasnext()) {
        // I Want Each Call to the next method to be its own transaction
        managedServiceHelper.transactionalMethod2(iter.next());
      }
    .
    .
    .
    }
    ManagedServiceHelper
    Code:
    /**
     * NOTE: NO transaction processed by Spring Here when called from ManagedService.nonTransactionalMethod().
     * @@RuleBasedTransactionAttribute(propagationBehaviorName="PROPAGATION_REQUIRED", isolationLevelName="ISOLATION_READ_COMMITTED")
     * @@RollbackRuleAttribute(Throwable.class)
     */
    void transactionalMethod2(Object object) {
    .
    .
    .
    }

    So, at this point, I need your input on the following:
    • Any suggestions on how to accomplish what I'm aiming for above?
    • Can someone please spell out clearly where transactions can be proxied and where they cannot?


    Thanks in advance.

    Erik

  2. #2
    Join Date
    Aug 2004
    Location
    Melbourne, Australia
    Posts
    1,104

    Default

    ...does NOT provide transaction support due to the fact that the proxy is not being used when a method within a Spring-Managed bean calls another method within a Spring-Managed bean ... even if the endpoint method is marked as transactional
    That's correct.

    I decided that my only (unfortunate) option was to refactor ManagedService.transactionalMethod2() into ManagedServiceHelper.transactionalMethod2()
    You could also refactor that code out into the non-manager object. It would be non-transactional and, within the loop, each invocation of ManagedService.transactionalMethod2() would be in it's own transaction as you want.

    I setup ManagedServiceHelper as a Spring-Managed Bean in the spring-config.xml, setup ManagedService to have an instance of ManagedServiceHelper provided to it by Dependency Injection
    As long as ManagedServiceHelper is wrapped in a transactional proxy this should work.

    Can someone please spell out clearly where transactions can be proxied and where they cannot?
    You've pretty much answered it where I've first quoted you. The Proxy contains the transaction logic, so it will work where ever you insert it with DI. If you bypass it with an internal call, the Proxy is not invoked, and so the transaction logic won't get applied.

Posting Permissions

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