需求
在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