事務回滾

 

需求
在service層的某個方法中,在執行完一個對數據庫的寫方法後,拋出異常,再執行另一個對數據庫的寫方法,爲什麼不會滾呢??是對Spring的事務機制就不明白。!! 
   默認spring事務只在發生未被捕獲的 runtimeexcetpion時纔回滾。  
   spring aop  異常捕獲原理:被攔截的方法需顯式拋出異常,並不能經任何處理,這樣aop代理才能捕獲到方法的異常,才能進行回滾,默認情況下aop只捕獲runtimeexception的異常,但可以通過  
    
配置來捕獲特定的異常並回滾  
  換句話說在service的方法中不使用try catch 或者在catch中最後加上throw new runtimeexcetpion(),這樣程序異常時才能被aop捕獲進而回滾


  解決方案: 
  方案1.例如service層處理事務,那麼service中的方法中不做異常捕獲,或者在catch語句中最後增加throw new RuntimeException()語句,以便讓aop捕獲異常再去回滾,並且在service上層(webservice客戶端,view層action)要繼續捕獲這個異常並處理
  方案2.在service層方法的catch語句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();語句,手動回滾,這樣上層就無需去處理異常(現在項目的做法)

 

僞代碼如下:

@Transactional
public void func() {
    dao.write(pojo1);
    throw new Exception("異常");
    dao.write(pojo2);
}

要求此時事務全部回滾,即pojo1和pojo2都不寫進數據庫。

單元測試代碼
    @Test
    public void testTransactional() {
        User user = new User();
        user.setUid(9);
        user.setUsername("李四");
        user.setPassword("234");
        userService.createAndUpdate(user);
    }


不回滾寫法
這種寫法保留了createUser方法對數據庫的寫操作,而不執行UpdateUser方法,結果是把創建的User對象李四寫進了數據庫,但並沒有重命名爲admin。原因是拋出異常並捕獲後,並沒有觸發事務回滾。所以代碼結束後李四保留在了數據庫中。

    @Override
    public void createAndUpdate(User user) {
        try {
            createUser(user);
            if (!user.getPassword().equals("123")) {
                throw new RuntimeException("密碼不是123");
            }
            user.setUsername("admin");
            updateUser(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

1

回滾寫法
寫法一:方法拋異常
這種寫法可以在方法處拋出異常,也可以不拋出(throws RuntimeException可寫可不寫)。

    @Override
    public void createAndUpdate(User user) throws RuntimeException {
        createUser(user);
        if (!user.getPassword().equals("123")) {
            throw new RuntimeException("密碼不是123");
        }
        user.setUsername("admin");
        updateUser(user);
    }

寫法二:try catch捕獲異常
這種方法相比於不回滾的那種寫法,只是在catch作用域內多加入了一行代碼:

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
1
完整方法:

    @Override
    public void createAndUpdate(User user) {
        try {
            createUser(user);
            if (!user.getPassword().equals("123")) {
                throw new RuntimeException("密碼不是123");
            }
            user.setUsername("admin");
            updateUser(user);
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }
原文:https://blog.csdn.net/qq_15329947/article/details/84974302 

 

 

 

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