简体   繁体   中英

Declarative Transaction Management in Spring behaving unpredictably

I have a Spring+Hibernate application with declarative transaction management. I have a service ( FooService ) which has 2 public methods MethodA and MethodB . The client will call the MethodA which in turn will call the MethodB .

Client -> MethodA -> MethodB

I want the transaction to start only from MethodB onwards. This is a snippet from my spring application-context:

<bean id="FooService"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="transactionManager" />
    <property name="target" ref="FooServiceTarget" />
    <property name="transactionAttributes">
      <props>
        <prop key="MethodB">PROPAGATION_REQUIRED,-FooException</prop>
      </props>
   </property>
</bean>

However, when I invoke the MethodA from my client, it doesn't create a transaction proxy when MethodB is to be called. If I add MethodA also to the bean configuration in application-context, the transaction proxy is invoked (starting MethodA , as expected). Why is this so? Can I achieve transaction being created only from MethodB onwards?

Client -> MethodA -> MethodB

I want the transaction to start only from MethodB onwards

This can't work. Method A and Method B are inside the same proxy.

The only proper thing to do is to move method B into a different Bean.

BTW: this has been asked many times before, here are some previous answers of mine:

Can I achieve transaction being created only from MethodB onwards?

Only if you use AspectJ bytecode weaving with Spring .

Why is this so?

Spring's default AOP mechanism is JDK dynamic proxies , which creates a separate Proxy instance that implements your service interface. This proxy is injected into other bean in place of your service, and all calls that go through it will do the transaction stuff before delegating to your service. Since a call from your service to itself doesn't go through the proxy, no transaction can or will be started. With AspectJ bytecode weaving, the transaction code will be woven directly into your service, and it will work fine. If you find yourself needing it for this purpose, though, it's a good bet that you need to refactor your "service" into at least two, separate objects because it's a signal that you've mixed up concerns and/or crossed abstraction layers in one class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM