程式碼丟擲異常後進行事務回滾的兩種方式(Spring @Transactional註解)
阿新 • • 發佈:2018-12-13
需求
在service層的某個方法中,在執行完一個對資料庫的寫方法後,丟擲異常,再執行另一個對資料庫的寫方法,虛擬碼如下:
@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(); } }
回滾寫法
寫法一:方法拋異常
這種寫法可以在方法處丟擲異常,也可以不丟擲(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();
完整方法:
@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();
}
}