一、@Transactional 注解在了非 public 方法上
- 如下所示
@Transactional
修饰在了非public
方法上
@Service
public class TestServiceImpl {
@Resource
private Test1Mapper test1Mapper;
@Transactional
protected Long save(Long seq){
Long aLong = Optional.ofNullable(seq).orElse(System.currentTimeMillis());
Test1Entity entity = new Test1Entity().setSeq(seq);
test1Mapper.insert(entity);
long l = entity.getId() / 0;
return entity.getId();
}
}
-
失效原因
Spring
中是通过动态代理来实现注解了@Transactional
的方法的事务处理操作,而在处理 @Transactional
的注解时是只对 public
方法才有效。
Spring
在扫描切点时,是根据注解进行判断是否创建切点。
AopUtils#canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions)
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
TransactionAttributeSourcePointcut# matches(Method method, Class<?> targetClass)
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
AnnotationTransactionAttributeSource#getTransactionAttribute
AnnotationTransactionAttributeSource#computeTransactionAttribute
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
return null;
}
-
解决方法
- 方法一:把需要支持事务的方法统一定义为
public
修饰的方法 - 方法二:创建一个全为
public
修饰的方法的门面类,在此类中添加@Transactional
二、在类内部调用添加 @Transactional 的方法
- 实例
@Service
public class TestServiceImpl {
@Resource
private Test1Mapper test1Mapper;
@Transactional
public void save(Long seq){
Long aLong = Optional.ofNullable(seq).orElse(System.currentTimeMillis());
test1Mapper.insert(new Test1Entity(null, seq));
long l = aLong / 0;
}
public void innerInvoke(){
this.save(100L);
}
}
- 失效原因
此种情况跟情况一的原因类似,在Spring
启动时会扫描所有添加了@Transactional
注解的类,创建的切面,当在同一个类中调用是,切面失去了作用。
- 解决方法
既然事务管理是基于动态代理对象的代理逻辑实现的,那么如果在类内部调用类内部的事务方法,这个调用事务方法的过程并不是通过代理对象来调用的,而是直接通过this对象来调用方法,绕过的代理对象,肯定就是没有代理逻辑了。
如下所示:
@Service
public class TestServiceImpl {
@Resource
private Test1Mapper test1Mapper;
@Resource
@Lazy
private TestServiceImpl test1Service;
@Transactional
public void save(Long seq){
Long aLong = Optional.ofNullable(seq).orElse(System.currentTimeMillis());
test1Mapper.insert(new Test1Entity(null, seq));
long l = aLong / 0;
}
public void innerInvoke(){
test1Service.save(100L);
}
}
三、捕获异常未抛出
- 实例
@Service
public class TestServiceImpl {
@Resource
private Test1Mapper test1Mapper;
@Transactional
public void save(Long seq){
try {
Long aLong = Optional.ofNullable(seq).orElse(System.currentTimeMillis());
test1Mapper.insert(new Test1Entity(null, seq));
long l = aLong / 0;
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 失效原因
事务方法内部捕捉了异常,没有抛出新的异常,导致事务操作不会进行回滚。
这种的话,可能我们比较常见,问题就出在代理逻辑中,我们先看看源码里卖弄动态代理逻辑是如何为我们管理事务的。
TransactionAspectSupport#invokeWithinTransaction
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
}
}
- 解决方法
- 方法一:在方法中不对异常进行捕获
- 方法二:若必须捕获,在捕获处理后在重新抛出异常。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)