如果我在Spring bean中的私有方法上有一个@Transactional -annotation,那么这个annotation有任何效果吗?

如果@Transactional注释位于公共方法上,则它将工作并打开事务。

public class Bean {
  public void doStuff() {
     doPrivateStuff();
  }
  @Transactional
  private void doPrivateStuff() {

  }
}

...

Bean bean = (Bean)appContext.getBean("bean");
bean.doStuff();

当前回答

默认情况下,@Transactional属性仅在对从applicationContext获得的引用调用带注释的方法时有效。

public class Bean {
  public void doStuff() {
    doTransactionStuff();
  }
  @Transactional
  public void doTransactionStuff() {

  }
}

这将打开一个事务:

Bean bean = (Bean)appContext.getBean("bean");
bean.doTransactionStuff();

这将不会:

Bean bean = (Bean)appContext.getBean("bean");
bean.doStuff();

Spring引用:使用@Transactional

Note: In proxy mode (which is the default), only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional! Consider the use of AspectJ mode (see below) if you expect self-invocations to be wrapped with transactions as well. In this case, there won't be a proxy in the first place; instead, the target class will be 'weaved' (i.e. its byte code will be modified) in order to turn @Transactional into runtime behavior on any kind of method.

其他回答

Spring文档解释了这一点

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Consider the use of AspectJ mode (see mode attribute in table below) if you expect self-invocations to be wrapped with transactions as well. In this case, there will not be a proxy in the first place; instead, the target class will be weaved (that is, its byte code will be modified) in order to turn @Transactional into runtime behavior on any kind of method.

另一种方法是使用BeanSelfAware

默认情况下,@Transactional属性仅在对从applicationContext获得的引用调用带注释的方法时有效。

public class Bean {
  public void doStuff() {
    doTransactionStuff();
  }
  @Transactional
  public void doTransactionStuff() {

  }
}

这将打开一个事务:

Bean bean = (Bean)appContext.getBean("bean");
bean.doTransactionStuff();

这将不会:

Bean bean = (Bean)appContext.getBean("bean");
bean.doStuff();

Spring引用:使用@Transactional

Note: In proxy mode (which is the default), only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional! Consider the use of AspectJ mode (see below) if you expect self-invocations to be wrapped with transactions as well. In this case, there won't be a proxy in the first place; instead, the target class will be 'weaved' (i.e. its byte code will be modified) in order to turn @Transactional into runtime behavior on any kind of method.

答案是否定的。请参见Spring参考:使用@Transactional :

@Transactional注释可以放在接口定义、接口上的方法、类定义或类上的公共方法之前

问题不是私有的或公共的,问题是:如何调用它以及您使用哪个AOP实现!

如果使用(默认)Spring Proxy AOP,那么只有在调用通过代理时才会考虑Spring提供的所有AOP功能(如@Transactional)。—如果从另一个bean调用带注释的方法,通常会出现这种情况。

这有两个含义:

因为不能从另一个bean调用私有方法(例外是反射),所以不会考虑它们的@Transactional Annotation。 如果方法是公共的,但它是从同一个bean调用的,那么它也不会被考虑在内(这句话只在(默认)使用Spring Proxy AOP的情况下是正确的)。

@参见Spring Reference: Chapter 9.6代理机制

恕我直言,您应该使用aspectJ模式,而不是Spring代理,这将克服这个问题。AspectJ事务方面甚至被编织到私有方法中(Spring 3.0检查)。

如果需要在事务中包装私有方法,而不想使用AspectJ,则可以使用TransactionTemplate。

@Service
public class MyService {
    @Autowired
    private TransactionTemplate transactionTemplate;

    private void process() {
        transactionTemplate.executeWithoutResult(status -> processInTransaction());
    }

    private void processInTransaction(){
        //...
    }
}