在咱們開發中不少時候都要用到事務,例如轉帳、充值等等的操做,這些我就很少BB了,因而不少人就選擇最簡單的方式@Transactional註解,可是你真的測試過事務異常的時候會回滾嗎?等生產環境遇到了在來查找緣由那就晚了,下面就說一下該註解的一下坑吧。程序員
沒有配置事務管理器。配置方式以下:面試
同一個類中,?一個未標註@Transactional的方法去調用標有@Transactional的方法,?事務會失效。數據庫
該註解只能應用到?public?可見度的方法上。?若是應用在protected、private或者?package可見度的方法上,也不會報錯,可是事務設置不會起做用。數組
數據庫引擎自己不支持事務,好比說MySQL數據庫中的myisam,事務是不起做用的。bash
Spring只會對unchecked異常進行事務回滾;若是是checked異常則不回滾。微信
那什麼是checked異常,什麼是unchecked異常?咱們把派生於Error或者RuntimeException的異常稱爲unchecked異常,全部其餘的異常成爲checked異常。什麼又是RuntimeException呢,用《Effective Java》上的一句話來講吧。架構
Use checked exceptions for recoverable conditions and runtime exceptions for programming errors (Item 58 in 2nd edition)測試
從這句話中咱們能夠簡單引伸一下,也就是說,若是出現了RuntimeException,就必定是程序員自身的問題。好比說,數組下標越界和訪問空指針異常等等,只要你稍加留心這些異常都是在編碼階段能夠避免的異常。ui
針對最後一種狀況,咱們簡單模擬一下吧,前期的準備工做這裏就跳過了,直接開始咱們今天的測試。測試以前數據庫中的emp表只有一條數據信息。 編碼
如今咱們先模擬正常狀況(RuntimeException, 咱們使用最簡單的數組越界異常。) 廢話很少說,直接上代碼:
@Test
@Transactional
public void test(){
Emp emp1 = new Emp();
emp1.setEmpname("測試二");
emp1.setEmail("test02@qq.com");
empService.insertEmp(emp1);
/**
* 模擬RuntimeException異常回滾
* */
int[] arr = {0};
System.out.println(arr[1]);//越界
Emp emp2 = new Emp();
emp2.setEmpname("測試三");
emp2.setEmail("test03@qq.com");
empService.insertEmp(emp1);
}
複製代碼
運行以後效果截圖:
程序運行以後,咱們看下數據庫的數據狀況: 代碼運行以後,因爲有RuntimeException異常拋出,因此事務回滾了,這兩條數據都沒保存成功。接下來模擬checked異常事務是否回滾問題,咱們強制拋出一個FileNotFoundException異常。 ?? 一樣的,這裏粘貼一下測試用的代碼:
@Test
@Transactional
public void test() throws Exception{
Emp emp1 = new Emp();
emp1.setEmpname("測試四");
emp1.setEmail("test04@qq.com");
empService.insertEmp(emp1);
/**
* 文件必定不存在
* */
FileInputStream file = new FileInputStream("C:\\Users\\pokemon\\Documents\\abc.txt");
Emp emp2 = new Emp();
emp2.setEmpname("測試五");
emp2.setEmail("test05@qq.com");
empService.insertEmp(emp1);
}
複製代碼
報錯狀況:
程序運行以後,咱們看下數據庫的數據狀況:
從上面的截圖能夠看出,事務並無回滾,empname是「測試四」的這條數據被寫入數據庫了。
等等,這種狀況咱們沒法預料,那應該怎麼辦?總不能坐以待斃吧。
這樣添加事務@Transactional(rollbackOn = Exception.class), 無論檢查異常仍是非檢查異常都會回滾。以上就是關於@Transactional註解事務的坑以及解決方案,若是感受對你有用,算我沒白忙活。
??歡迎你們關注個人微信公衆號"Java架構師養成記",不按期分享各種面試題、爬坑記錄。