如果我在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如果用于注释私有方法将没有任何影响。代理生成器将忽略它们。

Spring Manual第10.5.6章记录了这一点:

方法可见性和@Transactional 在使用代理时,应该应用代理 只有@Transactional注释 到具有公共可见性的方法。如果 注释protected, private或 类的包可见方法 @事务性注释,没有错误 ,但是带注释的方法 没有显示配置 事务设置。考虑到 如果需要,可以使用AspectJ(见下面) 注释非公共方法。

其他回答

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

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

你的问题的答案是否定的——@Transactional如果用于注释私有方法将没有任何影响。代理生成器将忽略它们。

Spring Manual第10.5.6章记录了这一点:

方法可见性和@Transactional 在使用代理时,应该应用代理 只有@Transactional注释 到具有公共可见性的方法。如果 注释protected, private或 类的包可见方法 @事务性注释,没有错误 ,但是带注释的方法 没有显示配置 事务设置。考虑到 如果需要,可以使用AspectJ(见下面) 注释非公共方法。

问题不是私有的或公共的,问题是:如何调用它以及您使用哪个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检查)。

与@loonis建议使用TransactionTemplate的方式相同,可以使用这个帮助组件(Kotlin):

@Component
class TransactionalUtils {
    /**
     * Execute any [block] of code (even private methods)
     * as if it was effectively [Transactional]
     */
    @Transactional
    fun <R> executeAsTransactional(block: () -> R): R {
        return block()
    }
}

用法:

@Service
class SomeService(private val transactionalUtils: TransactionalUtils) {

    fun foo() {
        transactionalUtils.executeAsTransactional { transactionalFoo() }
    }

    private fun transactionalFoo() {
        println("This method is executed within transaction")
    }
}

不知道TransactionTemplate是否重用现有事务,但这段代码肯定会重用。

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

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

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

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