内部调用事务失效
同一个service内,如果service调用的主方法上没有加事务注解,主方法的调用了该service的另一个有事务注解的方法,这个注解不会生效。
主要原因在于事务是通过AOP实现的,代理对象调用的方法上有事务注解,事务才会生效。
在同一个Service类中,只有由service代理类直接调用的方法能够被增强,调用类内部的时候对象不再是代理对象而是this即目标对象本身,另一个方法不能够再被增强,所以另一个方法的事务不能生效
如果主方法又不想加事务,另一个方法又想能够使用事务,就需要获取到这个代理对象来调用加事务的方法
有以下几种办法:
1.通过Spring上下文获取指定代理对象
@Autowired
private ApplicationContext applicationContext;
@Override
@Transactional
public Integer saveUserInfo(UserInfo userInfoParam){
UserInfo userInfo = userInfoRepository.save(userInfoParam);
if (true) {
throw new RuntimeException();
}
return userInfo.getId();
}
@Override
public void test(UserInfo userInfoParam) {
IUserInfoService userInfoService = applicationContext.getBean(IUserInfoService.class); //调用该类加事务注解的方法
userInfoService.saveUserInfo(userInfoParam);
}
2.通过Aop上下文获取当前代理对象
需要开启aop的exposeProxy属性,暴露代理对象:@EnableAspectJAutoProxy(exposeProxy = true)
使用AopContext.currentProxy()获取当前代理对象
@Override
@Transactional
public Integer saveUserInfo(UserInfo userInfoParam){
UserInfo userInfo = userInfoRepository.save(userInfoParam);
if (true) {
throw new RuntimeException();
}
return userInfo.getId();
}
@Override
public void test(UserInfo userInfoParam) {
IUserInfoService userInfoService = (IUserInfoService) AopContext.currentProxy();
//调用该类加事务注解的方法
userInfoService.saveUserInfo(userInfoParam);
}
3.直接通过@Autowired注入
@Autowired private IUserInfoService userInfoService;
异常回滚
使用@Transaction注解,默认只会回滚对 RuntimeException 和 Error 类型的异常回滚
TransactionAspectSupport管理事务切面,在增强的方法中如果捕获异常进入completeTransactionAfterThrowing()方法
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);
}
根据rollbackOn()方法判断是否回滚,默认情况下只有捕获的异常是RuntimeException、Error类型的才会返回ture
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
可以设置@Transaction注解的属性值,控制异常回滚:
rollbackFor
rollbackForClassName
noRollbackFor
noRollbackForClassName
例子:
下面代码会回滚抛出的Exception类型及其子类的异常,但不会回滚Error异常
@Override
@Transactional(rollbackFor = Exception.class) //如果要捕获所有异常应该写成 rollbackFor = Throwable.class public Integer saveUserInfo(UserInfo userInfoParam){
UserInfo userInfo = userInfoRepository.save(userInfoParam);
if (true) {
throw new Error();
}
return userInfo.getId();
}
下面代码会回滚除 InterruptedException、ClassNotFoundException 以外的异常
@Override
@Transactional(noRollbackForClassName = {"InterruptedException","ClassNotFoundException"})
public Integer saveUserInfo(UserInfo userInfoParam) throws InterruptedException, ClassNotFoundException {
UserInfo userInfo = userInfoRepository.save(userInfoParam);
if (true) {
throw new ClassNotFoundException();
}
return userInfo.getId();
}
|