Announcement Announcement Module
Collapse
No announcement yet.
How can I control the transaction order with ProxyFactoryBean Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    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...

    Comment


    • #3
      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?

      Comment


      • #4
        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?

        Comment


        • #5
          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).

          Comment


          • #6
            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

            Comment


            • #7
              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.

              Comment


              • #8
                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

                Comment

                Working...
                X