新聞中心
在 Spring Boot 中,造成事務不自動回滾的場景有很多,比如以下這些:

成都創(chuàng)新互聯(lián)公司,為您提供重慶網(wǎng)站建設公司、成都網(wǎng)站制作、網(wǎng)站營銷推廣、網(wǎng)站開發(fā)設計,對服務成都門簾等多個行業(yè)擁有豐富的網(wǎng)站建設及推廣經(jīng)驗。成都創(chuàng)新互聯(lián)公司網(wǎng)站建設公司成立于2013年,提供專業(yè)網(wǎng)站制作報價服務,我們深知市場的競爭激烈,認真對待每位客戶,為客戶提供賞心悅目的作品。 與客戶共同發(fā)展進步,是我們永遠的責任!
- 非 public 修飾的方法中的事務不自動回滾;
- 當 @Transactional 遇上 try/catch 事務不自動回滾;
- 調(diào)用類內(nèi)部的 @Transactional 方法事務不自動回滾;
- 拋出檢查異常時事務不自動回滾;
- 數(shù)據(jù)庫不支持事務,事務也不會自動回滾。
那么對于上面的這些場景,我們應該如何解決呢?接下來我們一一來看。
1、非 public 方法解決方案
?非 public 方法中事務不回滾的直接原因是,在非 public 方法上添加的 @Transactional 關(guān)鍵字是無效的,也就是此方法本身是以非事務的方式運行的,所以它當然不會自動回滾事務了。
因為 @Transactional 使用的是 Spring AOP 實現(xiàn)的,而 Spring AOP 是通過動態(tài)代理實現(xiàn)的,而 @Transactional 在生成代理時會判斷,如果方法為非 public 修飾的方法,則不生成代理對象,這樣也就沒辦法自動回滾事務了,它的部分實現(xiàn)源碼如下:
protected TransactionAttribute computeTransactionAttribute(Method method, Class> targetClass) {
// Don't allow no-public methods as required.
// 非 public 方法,設置為 null
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// 后面代碼省略....
}此問題的解決方案是將方法的權(quán)限修飾符改為 public 即可。
2、try/catch 解決方案
當程序中出現(xiàn)了 try/catch 代碼時,事務不會自動回滾,這是因為@Transactional 注解在其實現(xiàn)時,需要感知到異常才會自動回滾,而用戶自行在代碼中加入了 try/catch 之后,@Transactional 就無法感知到異常了,那么也就不能自動回滾事務了。
此問題的解決方案有兩種:一種是在 catch 中將異常重新拋出去,另一種是使用代碼手動將事務回滾。?
解決方案1:將異常重新拋出
解決方案2:使用代碼手動回滾事務
除了解決方案 1 這種不是很友好的回滾事務的方式之外,我們還可以選擇更加友好的,不報錯,但可以回滾事務的方式,其核心實現(xiàn)代碼如下:
3、調(diào)用內(nèi)部 @Transactional 方法解決方案
調(diào)用類內(nèi)部 @Transactional 的方法不自動回滾事務的原因是,@Transactional 是基于 Spring AOP 實現(xiàn)的,而 Spring AOP 又是基于動態(tài)代理實現(xiàn)的,而當調(diào)用類內(nèi)部的方法時,不是通過代理對象完成的,而是通過 this 對象實現(xiàn)的,這樣就繞過了代理對象,從而事務就失效了。
此時我們的解決方案是給調(diào)用的方法上也加上 @Transactional,具體實現(xiàn)代碼如下:
4、檢查異常的事務解決方案
所謂的檢查異常(Checked Excetion)指的是編譯器要求開發(fā)者必須處理的異常,如下圖所示:
?檢查異常不回滾事務的原因是因為,@Transactional 默認只回滾運行時異常 RuntimeException 和 Error,而對于檢查異常默認是不回滾的。
此問題的解決方案是給 @Transactional 注解上,添加 rollbackFor 參數(shù)并設置 Exception.class 值即可,具體實現(xiàn)代碼如下:
5、數(shù)據(jù)庫不支持事務的解決方案
?當我們在程序中添加了 @Transactional,相當于給調(diào)用的數(shù)據(jù)庫發(fā)送了:開始事務、提交事務、回滾事務的指令,但是如果數(shù)據(jù)庫本身不支持事務,比如 MySQL 中設置了使用 MyISAM 引擎,因為它本身是不支持事務的,這種情況下,即使在程序中添加了 @Transactional 注解,那么依然不會有事務的行為,也就不會執(zhí)行事務的自動回滾了。
在這種情況下,我們只需要設置 MySQL 的引擎為 InnoDB 就可以解決問題了,因為 InnoDB 是支持事務的,當然 MySQL 5.1 之后的默認引擎就是 InnoDB,引擎的設置分為以下兩種情況:
在新建表時設置數(shù)據(jù)庫引擎:
在修改表時設置數(shù)據(jù)庫引擎:
PS:也就是數(shù)據(jù)庫的引擎是和表直接相關(guān)的,我們只需要正確的設置引擎之后,事務就可以正常的執(zhí)行了。
總結(jié)
本文我們介紹了 5 種事務不自動回滾的場景和相應的解決方案,開發(fā)者應該根據(jù)自己的實際情況,選擇合適自己解決方案進行處理。
分享名稱:面試突擊:SpringBoot事務不回滾?怎么解決?
文章位置:http://www.5511xx.com/article/dpeipge.html


咨詢
建站咨詢
