從@Transactional註解看Spring事務

        在使用Spring事務時,我們只需在某方法上使用@Transactional註解簡單的標註一下,便可以實現很強大的事務控制功能,這其中的緣由,看小編娓娓道來;

         首先需要明確:在spring事務的切面中,實際上是一個Around切面,在註解的業務方法前後都可以被調用,而實際上實現切面操作的是TransactionInterceptor類;

[本篇我們先從實例代碼看該註解]

1)在代碼中使用@Transactional 註解,不設置事務的其他屬性,默認只對RuntimeException和Error進行回滾:

@Transactional
public void rollback() throws SQLException {
    // update db
    throw new SQLException("exception");
}

事實證明:上述的代碼並不會回滾;

2)對於需要回滾的異常,需要在註解中設置rollbackFor屬性,但這時,對於RuntimeException和Error的異常依舊會回滾:

@Transactional(rollbackFor = {SQLException.class})
public void rollback() throws SQLException {
    // update db
    throw new RuntimeException("exception");
}

在上述代碼片段中,雖然指定了SqlException,但方法體中的RuntimeException依舊會造成事務回滾;

3)嵌套事務

@Transactional
public void rollback() {
    // updateA
    try{
        selfProxy.innelTransaction()
    }catch(RuntimeException e){
        //do nothing
    }
    //updateC
}
  
@Transactional
public void innelTransaction() throws SQLException {
    // updateB
    throw new RuntimeException("exception");
}

在上述代碼中,innerTransaction方法中的異常並未攔截,在被rollback方法攔截之前,AOP已經獲取了異常,此時,當前事務的readOnly會被設置爲true,所以即使在rollback方法中進行了攔截和處理,代碼依舊會造成事務回滾;

產生以上現象的原因:

  內部方法(innelTransaction)拋出異常,觸發了回滾,這時當前事務被設置爲 rollback-only,當外部方法所在的事務提交時,Spring拋出以下異常,同時會將當前事務回滾;

org.springframework.transaction.UnexpectedRollbackException: 
           Transaction rolled back because it has been marked as rollback-only

在上述代碼中:

即使innelTransaction方法不加事務處理,依舊會有這個異常;

原因:在外部方法中,使用了一個事務,當內部方法拋出異常時,事務會被標記爲需要回滾,但是最終要在外部方法的事務提交時,校驗,spring的回滾標誌,檢測到回滾標記就會在回滾事務,並拋出UnexceptedRollbackException;

 

若要控制上述代碼不做回滾

1)我們需要在內部方法體中,將異常捕獲,通過Boolean返回值的方式來完成;

2)使用ServiceB的代理類來完成對functionB 的調用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章