总结
- 只支持public方法
- 无法支持内部调用
场景和原理分析
场景
- 只支持public方法
@Transactional
public List<Area> getAreaList(int pageNo, int pageSize) {
RowBounds rowBounds = new RowBounds(pageNo, pageSize);
return areaMapper.getAreaList(rowBounds);
}
- 无法支持内部调用
@Override
public List<Area> getAreaList(int pageNo, int pageSize) {
RowBounds rowBounds = new RowBounds(pageNo, pageSize);
return areaMapper.getAreaList(rowBounds);
transactionTest();
}
@Transactional
public void transactionTest(){
//假装有需要事务的操作
}
当然,idea还是很智能的
原理分析
我们都知道,spring的注解功能基本上都是通过spring aop,注解加切面才能完美的实现各种功能。当然,spring aop都是通过生成代理对象的方式实现的,也就是在代理对象中对你想要调用的方法进行了增强。
反之而言,你不使用代理对象,注解无效。接下来看@Transactional的实现方式。
在TransactionInterceptor中可以看到
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
而invokeWithinTransaction方法是使用调用TransactionAspectSupport中的方法,下面贴关键代码:
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
明显可以看到只是在方法前后进行了增强,也就是说内部调用方法未使用代理对象,无法进行增强也就无法开启事务。
@Transactional 只能应用到 public 方法才有效
只有@Transactional 注解应用到 public 方法,才能进行事务管理。这是因为在使用 Spring AOP 代理时,Spring 在调用在图 1 中的 TransactionInterceptor 在目标方法执行前后进行拦截之前,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource(Spring 通过这个类获取表 1. @Transactional 注解的事务属性配置属性信息)的 computeTransactionAttribute 方法。如图:
protected TransactionAttribute computeTransactionAttribute(Method method,
Class<?> targetClass) {
// Don't allow no-public methods as required.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;}
引用:https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html