1. 程式人生 > 其它 >解析spring事務管理@Transactional為什麼要新增rollbackFor=Exception.class

解析spring事務管理@Transactional為什麼要新增rollbackFor=Exception.class

spring中事務處理原理

    利用aop生成代理物件執行帶有Transactional事務註解的方法業務邏輯.專案啟動過程中會生成代理物件並將Transactional註解中的屬性進行解析載入處理.在方法執行過程中如果出現異常,會根據註解配置決定是進入到事務回滾處理還是事務提交處理邏輯中,事務回滾處理邏輯中最終還是基於資料庫的事務回滾處理.

異常的分類

案例說明

    以自定義異常為例說明一下@Transactional中是否指定rollbackFor=Exception.class的區別
    未指定rollbackFor屬性

       @Transactional
    @GetMapping(
"/addSysMenu") public void addSysMenu() throws Exception { // 更新選單名稱(將id為1的選單名修改為系統管理測試) int k = sysMenuDao.updateSysMenu(1, "系統管理測試"); System.out.println(k); // 自定義異常,丟擲非執行期異常 throw new Exception("自定義異常"); // 執行結果:程式終止,資料庫中選單id為1的選單名修改成功.說明事物沒有回滾. }

原因分析

    其他帖子都說如果不加的話僅支援執行期異常以及error錯誤型別.對於非執行期異常是不支援的.這裡提供一下這種說法的來源.
先看一下@Transactional註解中關於rollbackFor的使用說明

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    // 省略部分程式碼............
    // By default, a transaction will be rolling back on {@link RuntimeException} and {@link Error} but not on checked exceptions (business exceptions).
    
// 翻譯:指定事物回滾的異常型別,預設僅對於執行期異常和錯誤支援事務回滾,對於檢查異常(業務異常是不支援的) Class<? extends Throwable>[] rollbackFor() default {}; }

 至於加上@Transactional中指定rollbackFor=Exception.class以後是如何起作用的接著往下看.
spring中事務回滾的大概邏輯是,發生異常之後,會根據配置的事務屬性判斷是否進行回滾的處理,如果不進行事務回滾則直接進行事務提交.這裡重要的體現是在:TransactionAspectSupport.java中completeTransactionAfterThrowing

// 發生異常時事務處理方式
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
        if (txInfo != null && txInfo.getTransactionStatus() != null) {
            // 省略部分程式碼.......
            // 判斷異常是否為執行期異常或是error,如果是則執行回滾處理,如果不是則提交事務
            if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
                    // 回滾事務處理
                    txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
                    // 省略部分程式碼......
            }
            else {
                    // 提交事務
                    txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
                    // 省略部分程式碼.......
            }
        }
    }

 

而判斷事務是否支援回滾的處理在RuleBasedTransactionAttribute.java中transactionAttribute.rollbackOn()

// 判斷異常是否支援事務回滾處理
public boolean rollbackOn(Throwable ex) {
    
        RollbackRuleAttribute winner = null;
        // 省略部分程式碼....................
        // winner 是判斷@Transactional中是否有rollBackFor屬性,如果沒有則說明沒有指定,按照預設的方式進行判斷(DefaultTransactionAttribute.java中rollbackOn),如果有則只判斷是否屬於NoRollbackRuleAttribute型別,如果不是則說明支援事務回滾.關於變數win對應的RollbackRuleAttribute如何進行的賦值下面繼續.
        if (winner == null) {
            return super.rollbackOn(ex);
        }
        return !(winner instanceof NoRollbackRuleAttribute);
    }

    DefaultTransactionAttribute.java中rollbackOn,是否支援事務回滾的預設判斷方式:是否是執行期異常或是是否是錯誤型別(與Transactional註解中的rollbackFor屬性說明相對應).

public boolean rollbackOn(Throwable ex) {
        return (ex instanceof RuntimeException || ex instanceof Error);
    }

RollbackRuleAttribute中如何進行的賦值問題,具體來講是專案啟動之後會掃描帶有Transactional註解的方法,然後將註解中標註的屬性獲取之後進行引數配置.具體體現是在:SpringTransactionAnnotationParser.java中parseTransactionAnnotation

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
        RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
        // 省略部分程式碼.........
        // 獲取註解上的rollbackFor屬性值
        List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
        for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
            rollbackRules.add(new RollbackRuleAttribute(rbRule));
        }
        // 省略部分程式碼.........

        return rbta;
    }

 

   至此關於為什麼@Transactional為什麼要新增rollbackFor=Exception.class原因以講述完畢!

來源:解析spring事務管理@Transactional為什麼要新增rollbackFor=Exception.class_java_指令碼之家 (jb51.net)