@Transactional注解事務不回滾的原因


@Transactional注解只能應用到public可見度的方法上,可以被應用於接口定義和接口方法,方法會覆蓋類上面聲明的事務。

常見坑點1:遇到檢查異常時,事務開啟,也無法回滾。 例如下面這段代碼,用戶依舊增加成功,並沒有因為后面遇到檢查異常而回滾!!

@Transactional
public int insertUser(User user) throws Exception{
    // 新增用戶信息
    int rows = userMapper.insertUser(user);
    // 新增用戶崗位關聯
    insertUserPost(user);
    // 新增用戶與角色管理
    insertUserRole(user);
    // 模擬拋出SQLException異常
    boolean flag = true;
    if (flag){
        throw new SQLException("發生異常了..");
    }
    return rows;
}

原因分析:因為Spring的默認的事務規則是遇到運行異常(RuntimeException)和程序錯誤(Error)才會回滾。如果想針對非檢查異常進行事務回滾,可以在@Transactional 注解里使用 rollbackFor 屬性明確指定異常。

例如下面這樣,就可以正常回滾:

@Transactional(rollbackFor = Exception.class)
public int insertUser(User user) throws Exception{
    // 新增用戶信息
    int rows = userMapper.insertUser(user);
    // 新增用戶崗位關聯
    insertUserPost(user);
    // 新增用戶與角色管理
    insertUserRole(user);
    // 模擬拋出SQLException異常
    boolean flag = true;
    if (flag){
        throw new SQLException("發生異常了..");
    }
    return rows;
}

常見坑點2: 在業務層捕捉異常后,發現事務不生效。 這是許多新手都會犯的一個錯誤,在業務層手工捕捉並處理了異常,你都把異常“吃”掉了,Spring自然不知道這里有錯,更不會主動去回滾數據。
例如:下面這段代碼直接導致用戶新增的事務回滾沒有生效。

@Transactional
public int insertUser(User user) throws Exception{
    // 新增用戶信息
    int rows = userMapper.insertUser(user);
    // 新增用戶崗位關聯
    insertUserPost(user);
    // 新增用戶與角色管理
    insertUserRole(user);
    // 模擬拋出SQLException異常
    boolean flag = true;
    if (flag) {
        try{
            // 謹慎:盡量不要在業務層捕捉異常並處理
            throw new SQLException("發生異常了..");
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }
    return rows;
}

推薦做法:在業務層統一拋出異常,然后在控制層統一處理。

@Transactional
public int insertUser(User user) throws Exception
{
    // 新增用戶信息
    int rows = userMapper.insertUser(user);
    // 新增用戶崗位關聯
    insertUserPost(user);
    // 新增用戶與角色管理
    insertUserRole(user);
    // 模擬拋出SQLException異常
    boolean flag = true;
    if (flag)
    {
        throw new RuntimeException("發生異常了..");
    }
    return rows;
}

Transactional注解的常用屬性表:

屬性 說明
propagation 事務的傳播行為,默認值為 REQUIRED。
isolation 事務的隔離度,默認值采用 DEFAULT
timeout 事務的超時時間,默認值為-1,不超時。如果設置了超時時間(單位秒),那么如果超過該時間限制了但事務還沒有完成,則自動回滾事務。
read-only 指定事務是否為只讀事務,默認值為 false;為了忽略那些不需要事務的方法,比如讀取數據,可以設置 read-only 為 true。
rollbackFor 用於指定能夠觸發事務回滾的異常類型,如果有多個異常類型需要指定,各類型之間可以通過逗號分隔。{xxx1.class, xxx2.class,……}
noRollbackFor 拋出 no-rollback-for 指定的異常類型,不回滾事務。{xxx1.class, xxx2.class,……}

 


免責聲明!

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



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