99%的Java程序員都不知道的Spring中的@Transactional註解的坑

  在咱們開發中不少時候都要用到事務,例如轉帳、充值等等的操做,這些我就很少BB了,因而不少人就選擇最簡單的方式@Transactional註解,可是你真的測試過事務異常的時候會回滾嗎?等生產環境遇到了在來查找緣由那就晚了,下面就說一下該註解的一下坑吧。程序員

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表只有一條數據信息。 編碼

image

unchecked異常事務回滾驗證

  如今咱們先模擬正常狀況(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);
    }
複製代碼

  運行以後效果截圖:

image
  程序運行以後,咱們看下數據庫的數據狀況:
image
  代碼運行以後,因爲有RuntimeException異常拋出,因此事務回滾了,這兩條數據都沒保存成功。

checked異常事務回滾驗證

  接下來模擬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);
    }
複製代碼

  報錯狀況:

image

  程序運行以後,咱們看下數據庫的數據狀況:

image

  從上面的截圖能夠看出,事務並無回滾,empname是「測試四」的這條數據被寫入數據庫了。

  等等,這種狀況咱們沒法預料,那應該怎麼辦?總不能坐以待斃吧。

解決方案

  這樣添加事務@Transactional(rollbackOn = Exception.class), 無論檢查異常仍是非檢查異常都會回滾。以上就是關於@Transactional註解事務的坑以及解決方案,若是感受對你有用,算我沒白忙活。

??歡迎你們關注個人微信公衆號"Java架構師養成記",不按期分享各種面試題、爬坑記錄。

Java架構師養成記.jpg
相關文章
相關標籤/搜索