Results 1 to 8 of 8

Thread: How can I control the transaction order with ProxyFactoryBean

  1. #1

    Default How can I control the transaction order with ProxyFactoryBean

    Hi there,

    I have @Transactional annotation on a Bean and I am using tx:annotation-driven with 2.5.6

    On this bean I have a set of interceptors that perform additional logic, defined by a ProxyFactoryBean. The problem here is that the transaction starts after my interceptor and ends before the post processing of the transactional method call. One of the interceptor must be in the same transactional context as the method call. Is there any way to force the transactional interceptor in the ProxyFactoryBean maybe?

    I tried to switch to plain aop with ordered advices but I had tons of issues with BeanInCreationException and Proxy issues.

    Thx,
    S.

  2. #2
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,625

    Default

    I strongly suggest changing to the AOP stuff because that is much easier to control than an ProxyFactoryBean (next to the reduced xml). So if you can post some configuration we might be able to figure out what is wrong...
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  3. #3

    Default

    I know. Basically, as soon as I turned on aop:config, some "unrelated" beans caused issues: BeanInCreationException, could not convert Proxy$12 to class foo, etc, etc.

    See

    http://forum.springframework.org/showthread.php?t=67501
    http://forum.springframework.org/showthread.php?t=67502

    We're close to releasing this application and when I see the number of changes that I had to made to make it work with *ONE* advice on *ONE* bean. In short, with a simple aop:config, I have the following problems:

    * Could not use constructor injection anymore (I had to remove final from many beans)
    * I cannot even inject standard stuff like SimpleJdbcTemplate without specifying it as a SimpleJdbcOperations. There is no advice on it, I am not extending it either in my app
    * I cannot inject HibernateTemplate in my generic DAO
    * At some point it works with depends-on="hibernateTemplate" lazy-init="true"

    There's too much things that I don't understand to do the move. I just want to do a small change to a single service that is failing for the moment because the MethodInterceptor does not run in the transaction

    I guess that if I remove @Transactional on it and I use the TransactionProxyFactoryBean that would work, right?

  4. #4

    Arrow

    For those who are interested, here's how I did it

    Code:
    <bean id="baseRemoteServiceProxy"
              class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
              abstract="true">
            <property name="transactionManager" ref="transactionManager"/>
            <property name="transactionAttributes">
                <props>
                    <prop key="persist*">PROPAGATION_REQUIRED</prop>
                    <prop key="update*">PROPAGATION_REQUIRED</prop>
                    <prop key="remove*">PROPAGATION_REQUIRED</prop>
                    <prop key="harvest*">PROPAGATION_REQUIRED</prop>
                    <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
                </props>
            </property>
            <property name="preInterceptors">
                <list>
                    <ref bean="remoteExceptionInterceptor"/>
                </list>
            </property>
            <property name="postInterceptors">
                <list>
                    <ref bean="entityAfterAdvice"/>
                    <ref bean="clientToServerAdvice"/>
                </list>
            </property>
        </bean>
    As you can see the exception interceptor is called last, which means it can also intercepts the exceptions related to the transaction commit. The two other advices that must run in a transaction are set in the post interceptors so that the transaction is available to them there. With this base proxy I just have to create the actualy remote proxy with this simple definition

    Code:
     <bean id="remoteCatalogServiceProxy" parent="baseRemoteServiceProxy">
            <property name="proxyInterfaces" value="com.foo.remote.RemoteCatalogService"/>
            <property name="target">
                <bean class="com.foo.service.catalog.RemoteCatalogServiceImpl">
                    <constructor-arg ref="catalogService"/>
                    <constructor-arg ref="entityFactory"/>
                </bean>
            </property>
        </bean>
    I would prefer to use AOP, trust me, but activating it on my config lead to too many issues.

    And now I have another issue, nice.

    Code:
    org.springframework.transaction.IllegalTransactionStateException : Pre-bound JDBC Connection found! HibernateTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single HibernateTransactionManager for all transactions on a single DataSource, no matter whether Hibernate or JDBC access.
    If only have a transaction manager of course. Does spring support a mix of transactionfactory bean and @Transactional?

  5. #5
    Join Date
    May 2007
    Location
    Saint Petersburg, Russian Federation
    Posts
    1,189

    Default

    Quote Originally Posted by snicoll View Post
    ...
    Does spring support a mix of transactionfactory bean and @Transactional?
    No such ability is implemented for annotation-based approach. You can define transaction manager per-<tx:advice> using schema-based transaction configuration approach. (check the reference for such an example).

  6. #6

    Default

    Quote Originally Posted by denis.zhdanov View Post
    No such ability is implemented for annotation-based approach. You can define transaction manager per-<tx:advice> using schema-based transaction configuration approach. (check the reference for such an example).
    I did. Nothing says that I can't have TransactionInterceptor and @Transactional in the same application (I am not talking about the same beans here). My remote facade has a TransactionInterceptor (see above) and it calls another beans that has @Transactional on it.

    To me it should work but it seems that the internal bean that uses HibernateTemplate does not realize the the transaction was already started somehow. See also http://jira.springframework.org/browse/SPR-5033

  7. #7

    Default

    Quote Originally Posted by snicoll View Post
    For those who are interested, here's how I did it

    Code:
    <bean id="baseRemoteServiceProxy"
              class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
              abstract="true">
            <property name="transactionManager" ref="transactionManager"/>
            <property name="transactionAttributes">
                <props>
                    <prop key="persist*">PROPAGATION_REQUIRED</prop>
                    <prop key="update*">PROPAGATION_REQUIRED</prop>
                    <prop key="remove*">PROPAGATION_REQUIRED</prop>
                    <prop key="harvest*">PROPAGATION_REQUIRED</prop>
                    <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
                </props>
            </property>
            <property name="preInterceptors">
                <list>
                    <ref bean="remoteExceptionInterceptor"/>
                </list>
            </property>
            <property name="postInterceptors">
                <list>
                    <ref bean="entityAfterAdvice"/>
                    <ref bean="clientToServerAdvice"/>
                </list>
            </property>
        </bean>
    As you can see the exception interceptor is called last, which means it can also intercepts the exceptions related to the transaction commit. The two other advices that must run in a transaction are set in the post interceptors so that the transaction is available to them there. With this base proxy I just have to create the actualy remote proxy with this simple definition

    Code:
     <bean id="remoteCatalogServiceProxy" parent="baseRemoteServiceProxy">
            <property name="proxyInterfaces" value="com.foo.remote.RemoteCatalogService"/>
            <property name="target">
                <bean class="com.foo.service.catalog.RemoteCatalogServiceImpl">
                    <constructor-arg ref="catalogService"/>
                    <constructor-arg ref="entityFactory"/>
                </bean>
            </property>
        </bean>
    I would prefer to use AOP, trust me, but activating it on my config lead to too many issues.

    And now I have another issue, nice.

    Code:
    org.springframework.transaction.IllegalTransactionStateException : Pre-bound JDBC Connection found! HibernateTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single HibernateTransactionManager for all transactions on a single DataSource, no matter whether Hibernate or JDBC access.
    If only have a transaction manager of course. Does spring support a mix of transactionfactory bean and @Transactional?
    OK, this is working now. One of my interceptor had a flaw as it opened an hibernate session if necessary but was closing it, no matter if it created it or not. As a result the session was always closed before the transaction actually commits. Fixing the bug fixes the issue.

  8. #8
    Join Date
    Jan 2008
    Location
    Mohnton, PA USA (that's near Philadelphia)
    Posts
    2,148

    Default

    Back to Marten's quote:
    I strongly suggest changing to the AOP stuff because that is much easier to control than an ProxyFactoryBean (next to the reduced xml). So if you can post some configuration we might be able to figure out what is wrong...
    I still don't understand why can't you use something like this:
    Code:
    <aop:config>
       <aop:pointcut id=“myPointcut”
                    expression=“execution(public * foo..Foo+.*(..))”/>
    <aop:advisor pointcut-ref=“myPointcut” advice-ref=“remoteExceptionInterceptor”/>
       <aop:advisor pointcut-ref=“myPointcut” advice-ref=“txAdvice”/>
    <aop:advisor pointcut-ref=“myPointcut” advice-ref=“entityAfterAdvice”/>
    <aop:advisor pointcut-ref=“myPointcut” advice-ref=“clientToServerAdvice”/>
    </aop:config>
    You can also specify order attribute to manage order explicitly

Posting Permissions

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