开发者

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:

  • Understanding Spring transactions - What happens when a transactional method calls another transactional method?
  • Spring @Transactional method - participating transaction
  • One Service method invoke inner multiple method for Spring transaction


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜