溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

發(fā)布時間:2021-11-18 13:06:16 來源:億速云 閱讀:219 作者:小新 欄目:開發(fā)技術(shù)

這篇文章給大家分享的是有關(guān)如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

一、 spring 事務(wù)原理

一、Spring事務(wù)原理

在使用JDBC事務(wù)操作數(shù)據(jù)庫時,流程如下:

//獲取連接 
1.Connection con = DriverManager.getConnection()
//開啟事務(wù)
2.con.setAutoCommit(true/false);
3.執(zhí)行CRUD
//提交事務(wù)/回滾事務(wù) 
4. con.commit() / con.rollback();
//關(guān)閉連接
5. conn.close();

Spring本身并不提供事務(wù),而是對JDBC事務(wù)通過AOP做了封裝,隱藏了2和4的操作,簡化了JDBC的應(yīng)用。

spring對JDBC事務(wù)的封裝,是通過AOP動態(tài)代理來實現(xiàn)的,在調(diào)用目標方法(也就是第3步)前后會通過代理類來執(zhí)行事務(wù)的開啟、提交或者回滾操作。
spring事務(wù)使用的兩個不可忽略點:

注意關(guān)鍵詞 “動態(tài)代理”,這意味著要生成一個代理類,那么我們就不能在一個類內(nèi)直接調(diào)用事務(wù)方法,否則無法代理,而且該事務(wù)方法必須是public,如果定義成 protected、private 或者默認可見性,則無法調(diào)用!

問題一、@Transactional 應(yīng)該加到什么地方,如果加到Controller會回滾嗎?

@Transactional 最好加到service層,加到Controller層也是生效的,但是為了規(guī)范起見,還是加到service層上。

下載代碼并啟動難項目進行驗證:主要代碼如下:
Controller層代碼如下:

 @Autowired
    private TransactionalService transactionalService;

    @Autowired
    private UserDao userDao;

    @Autowired
    private JwtUserDao jwtUserDao;

    /**
     * 測試@Transactional 注解加到service層事務(wù)是否回滾
     */
    @RequestMapping("/tx")
    public void serviceTX(){
        transactionalService.controllerTX();
    }
    /**
     * 測試@Transactional 注解加到Controller層事務(wù)是否回滾
     */
    @Transactional(rollbackFor = Exception.class)
    @RequestMapping("/ctx2")
    public void cTX2(){
        userDao.update();
        System.out.println(2/0);
        jwtUserDao.update();
    }

 /**
     * 測試@Transactional 注解加到Controller層事務(wù)是否回滾
     * 這里在Controller層為了方便直接調(diào)用了dao層,在實際開發(fā)中dao層即可在Controller層調(diào)用也可以在service層調(diào)用,
     * 比如service層只是直接調(diào)用dao層一個方法,此外沒有任何操作,那么這時候完全不用寫service層的方法,直接在Controller調(diào)用dao層即可,
     * 當然如果公司有規(guī)范,必須嚴格按照mvc的模式進行開發(fā),則另說
     */
    @Transactional(rollbackFor = Exception.class)
    @RequestMapping("/ctx2")
    public void cTX2(){
        userDao.update();
         //手動拋出一個RuntimeException
        System.out.println(2/0);
        jwtUserDao.update();
    }

service層的主要代碼

 @Autowired
    private UserDao userDao;

    @Autowired
    private  JwtUserDao  jwtUserDao;

    @Transactional(rollbackFor = Exception.class)
    public void controllerTX(){
        userDao.update();
         //手動拋出一個RuntimeException
        System.out.println(2/0);
        jwtUserDao.update();
    }

dao層sql語句如下:

 <update id="update">
        UPDATE jwt_user SET username ='wangwuupdate' WHERE user_id= 2
    </update>
    
 <update id="update">
        UPDATE user SET username ='zsupdate' WHERE id= 2
    </update>

數(shù)據(jù)庫原始數(shù)據(jù):

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

瀏覽器中輸入:http://localhost:8081/tx/tx,由于本次使用測試代碼進行統(tǒng)一的異常處理所以瀏覽器的返回數(shù)據(jù)如下:

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

控制臺輸出如下:

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

查看數(shù)據(jù)庫中的數(shù)據(jù)并沒有被修改
瀏覽器中輸入:http://localhost:8081/tx/ctx2,

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

查看數(shù)據(jù)庫中的數(shù)據(jù)并沒有被修改
由此可以得出 :@Transactional 加到Controller層也是生效的,但是為了規(guī)范起見,還是加到service層上。

問題二、 @Transactional 注解中用不用加rollbackFor = Exception.class 這個屬性值

spring的api doc中有折磨一句描述:

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

紅框中的內(nèi)容如下:

rolling back on RuntimeException and Error but not on checked exceptions

大致意思就默認情況下,當程序發(fā)生 RuntimeException 和 Error 的這兩種異常的時候事務(wù)會回滾,但是如果發(fā)生了checkedExcetions ,如fileNotfundException 則不會回滾,所以 rollbackFor = Exception.class 這個一定要加!
驗證如下:
瀏覽器輸入:http://localhost:8081/tx/ctx3
控制臺輸出如下:

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

這時候查看數(shù)據(jù)庫中的數(shù)據(jù)并沒有被修改
瀏覽器輸入:http://localhost:8081/tx/ctx4

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

這時候查看數(shù)據(jù)庫數(shù)據(jù)已經(jīng)被修改:

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題

問題三:事務(wù)調(diào)用嵌套問題具體結(jié)果如下代碼:

/**
     * 同類中在方法a中調(diào)用b
     * a沒有事務(wù),b有 ,異常發(fā)生在b中 不會回滾
     */
    @RequestMapping("/a1")
    public void a1(){
        transactionalService.a1();
    }

    /**
     * 同類中在方法a中調(diào)用b
     * a沒有事務(wù),b有 ,異常發(fā)生在a中 不會回滾
     */
    @RequestMapping("/a2")
    public void a2(){
        transactionalService.a2();
    }
    /**
     * 同類中在方法a中調(diào)用b
     * a有事務(wù),b沒有 ,異常發(fā)生在b中 會回滾
     */
    @RequestMapping("/a3")
    public void a3(){
        transactionalService.a3();
    }
    /**
     * 同類中在方法a中調(diào)用b
     * a有事務(wù),b沒有 ,異常發(fā)生在a中 會回滾
     */
    @RequestMapping("/a4")
    public void a4(){
        transactionalService.a4();
    }
    /**
     * 同類中在方法a中調(diào)用b
     * a有事務(wù),b也有 ,異常發(fā)生在b中 會回滾
     */
    @RequestMapping("/a5")
    public void a5(){
        transactionalService.a5();
    }
    /**
     * 同類中在方法a中調(diào)用b
     * a有事務(wù),b也有 ,異常發(fā)生在a中 會回滾
     */
    @RequestMapping("/a6")
    public void a6(){
        transactionalService.a6();
    }


    /**
     *a類中調(diào)用b類中的方法
     * a中有事務(wù),b中也有 會回滾
     *
     */
    @RequestMapping("/b5")
    public  void b5(){
        transactionalService.b5();
    }

    /**
     *a類中調(diào)用b類中的方法
     * a中有事務(wù),b中沒有 會回滾
     *
     */
    @RequestMapping("/b6")
    public  void b6(){
        transactionalService.b6();
    }

    /**
     *a類中調(diào)用b類中的方法
     * a沒有事務(wù),b中有 不會回滾
     *
     */
    @RequestMapping("/b7")
    public  void b7(){
        transactionalService.b7();
    }

    /**
     *a類中調(diào)用b類中的方法
     * a沒有事務(wù),b中沒有 不會回滾
     *
     */
    @RequestMapping("/b8")
    public  void b8(){
        transactionalService.b8();
    }

如果在a方法中調(diào)用b方法不管是不是a和b是不是在同一個類中,只要a方法中沒有事務(wù),則發(fā)生異常的時候不會回滾,即:當a無事務(wù)時,則a和b均沒有事務(wù),當a有事務(wù)時,b如果有事務(wù),則b事務(wù)會加到a事務(wù)中,二者為同一事務(wù)!

感謝各位的閱讀!關(guān)于“如何解決spring聲明式事務(wù)@Transactional不回滾的多種情況問題”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI