Spring事务总结(一) 内部调用事务失效、异常回滚

内部调用事务失效

同一个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();
    }

 

猜你喜欢

转载自www.cnblogs.com/gss128/p/12121303.html