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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM