SpringBoot事務(wù)不回滾的解決方案
在 Spring Boot 中,造成事務(wù)不自動(dòng)回滾的場(chǎng)景有很多,比如以下這些:
- 非 public 修飾的方法中的事務(wù)不自動(dòng)回滾;
- 當(dāng) @Transactional 遇上 try/catch 事務(wù)不自動(dòng)回滾;
- 調(diào)用類內(nèi)部的 @Transactional 方法事務(wù)不自動(dòng)回滾;
- 拋出檢查異常時(shí)事務(wù)不自動(dòng)回滾;
- 數(shù)據(jù)庫(kù)不支持事務(wù),事務(wù)也不會(huì)自動(dòng)回滾。
那么對(duì)于上面的這些場(chǎng)景,我們應(yīng)該如何解決呢?接下來(lái)我們一一來(lái)看。
1.非 public 方法解決方案
非 public 方法中事務(wù)不回滾的直接原因是,在非 public 方法上添加的 @Transactional 關(guān)鍵字是無(wú)效的,也就是此方法本身是以非事務(wù)的方式運(yùn)行的,所以它當(dāng)然不會(huì)自動(dòng)回滾事務(wù)了。
因?yàn)?@Transactional 使用的是 Spring AOP 實(shí)現(xiàn)的,而 Spring AOP 是通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)的,而 @Transactional 在生成代理時(shí)會(huì)判斷,如果方法為非 public 修飾的方法,則不生成代理對(duì)象,這樣也就沒(méi)辦法自動(dòng)回滾事務(wù)了,它的部分實(shí)現(xiàn)源碼如下:
protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) { // Don't allow no-public methods as required. // 非 public 方法,設(shè)置為 null if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } // 后面代碼省略.... }
此問(wèn)題的解決方案是將方法的權(quán)限修飾符改為 public 即可。
2.try/catch 解決方案
當(dāng)程序中出現(xiàn)了 try/catch 代碼時(shí),事務(wù)不會(huì)自動(dòng)回滾,這是因?yàn)?@Transactional 注解在其實(shí)現(xiàn)時(shí),需要感知到異常才會(huì)自動(dòng)回滾,而用戶自行在代碼中加入了 try/catch 之后,@Transactional 就無(wú)法感知到異常了,那么也就不能自動(dòng)回滾事務(wù)了。
此問(wèn)題的解決方案有兩種:一種是在 catch 中將異常重新拋出去,另一種是使用代碼手動(dòng)將事務(wù)回滾。
解決方案1:將異常重新拋出
解決方案2:使用代碼手動(dòng)回滾事務(wù)
除了解決方案 1 這種不是很友好的回滾事務(wù)的方式之外,我們還可以選擇更加友好的,不報(bào)錯(cuò),但可以回滾事務(wù)的方式,其核心實(shí)現(xiàn)代碼如下:
3.調(diào)用內(nèi)部 @Transactional 方法解決方案
調(diào)用類內(nèi)部 @Transactional 的方法不自動(dòng)回滾事務(wù)的原因是,@Transactional 是基于 Spring AOP 實(shí)現(xiàn)的,而 Spring AOP 又是基于動(dòng)態(tài)代理實(shí)現(xiàn)的,而當(dāng)調(diào)用類內(nèi)部的方法時(shí),不是通過(guò)代理對(duì)象完成的,而是通過(guò) this 對(duì)象實(shí)現(xiàn)的,這樣就繞過(guò)了代理對(duì)象,從而事務(wù)就失效了。
此時(shí)我們的解決方案是給調(diào)用的方法上也加上 @Transactional,具體實(shí)現(xiàn)代碼如下:
4.檢查異常的事務(wù)解決方案
所謂的檢查異常(Checked Excetion)指的是編譯器要求開(kāi)發(fā)者必須處理的異常,如下圖所示:
檢查異常不回滾事務(wù)的原因是因?yàn)?,@Transactional 默認(rèn)只回滾運(yùn)行時(shí)異常 RuntimeException 和 Error,而對(duì)于檢查異常默認(rèn)是不回滾的。
此問(wèn)題的解決方案是給 @Transactional 注解上,添加 rollbackFor 參數(shù)并設(shè)置 Exception.class 值即可,具體實(shí)現(xiàn)代碼如下:
5.數(shù)據(jù)庫(kù)不支持事務(wù)的解決方案
當(dāng)我們?cè)诔绦蛑刑砑恿?@Transactional,相當(dāng)于給調(diào)用的數(shù)據(jù)庫(kù)發(fā)送了:開(kāi)始事務(wù)、提交事務(wù)、回滾事務(wù)的指令,但是如果數(shù)據(jù)庫(kù)本身不支持事務(wù),比如 MySQL 中設(shè)置了使用 MyISAM 引擎,因?yàn)樗旧硎遣恢С质聞?wù)的,這種情況下,即使在程序中添加了 @Transactional 注解,那么依然不會(huì)有事務(wù)的行為,也就不會(huì)執(zhí)行事務(wù)的自動(dòng)回滾了。
在這種情況下,我們只需要設(shè)置 MySQL 的引擎為 InnoDB 就可以解決問(wèn)題了,因?yàn)?InnoDB 是支持事務(wù)的,當(dāng)然 MySQL 5.1 之后的默認(rèn)引擎就是 InnoDB,引擎的設(shè)置分為以下兩種情況:
在新建表時(shí)設(shè)置數(shù)據(jù)庫(kù)引擎:
在修改表時(shí)設(shè)置數(shù)據(jù)庫(kù)引擎
PS:也就是數(shù)據(jù)庫(kù)的引擎是和表直接相關(guān)的,我們只需要正確的設(shè)置引擎之后,事務(wù)就可以正常的執(zhí)行了。
總結(jié)
本文我們介紹了 5 種事務(wù)不自動(dòng)回滾的場(chǎng)景和相應(yīng)的解決方案,開(kāi)發(fā)者應(yīng)該根據(jù)自己的實(shí)際情況,選擇合適自己解決方案進(jìn)行處理。
到此這篇關(guān)于SpringBoot事務(wù)不回滾的解決方案的文章就介紹到這了,更多相關(guān)SpringBoot事務(wù)不回滾內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot手動(dòng)事務(wù)回滾的實(shí)現(xiàn)代碼
- 使用SpringBoot注解方式處理事務(wù)回滾實(shí)現(xiàn)
- springboot使用mybatis開(kāi)啟事務(wù)回滾
- SpringBoot中的事務(wù)回滾規(guī)則詳解
- SpringBoot中進(jìn)行事務(wù)回滾的方法
- SpringBoot 多線程事務(wù)回滾的實(shí)現(xiàn)
- SpringBoot 回滾操作的幾種實(shí)現(xiàn)方式
- Springboot結(jié)合Mybatis-Plus實(shí)現(xiàn)業(yè)務(wù)撤銷回滾功能
相關(guān)文章
java?數(shù)組越界判斷和獲取數(shù)組長(zhǎng)度的實(shí)現(xiàn)方式
這篇文章主要介紹了java?數(shù)組越界判斷和獲取數(shù)組長(zhǎng)度的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12工廠方法模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了工廠方法模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理的相關(guān)資料,需要的朋友可以參考下2017-08-08Java連接 JDBC基礎(chǔ)知識(shí)(操作數(shù)據(jù)庫(kù):增刪改查)
這篇文章主要介紹了Java連接 JDBC基礎(chǔ)知識(shí),包括操作數(shù)據(jù)庫(kù)之增刪改查操作,需要的朋友可以參考下2021-04-04Java的Struts框架中的if/else標(biāo)簽使用詳解
這篇文章主要介紹了Java的Struts框架中的if/else標(biāo)簽使用詳解,Struts是Java的SSH三大web開(kāi)發(fā)框架之一,需要的朋友可以參考下2015-12-12Java?SpringBoot?獲取接口實(shí)現(xiàn)類匯總
這篇文章主要介紹了Java?SpringBoot?獲取接口實(shí)現(xiàn)類匯總,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09使用Feign配置請(qǐng)求頭以及支持Https協(xié)議
這篇文章主要介紹了使用Feign配置請(qǐng)求頭以及支持Https協(xié)議,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03SpringBoot中的RestTemplate使用方法詳解
這篇文章主要介紹了SpringBoot中的RestTemplate使用方法詳解,為了方便使用,這里我封裝成一個(gè)工具類來(lái)靜態(tài)調(diào)用RestTemplate,基于SpringBoot2.4.2版本,需要的朋友可以參考下2024-01-01SpringBoot使用DevTools實(shí)現(xiàn)后端熱部署的過(guò)程詳解
在Spring Boot項(xiàng)目中,Spring Boot官方提供你了Devtools熱部署模塊,通過(guò)maven的方式導(dǎo)入就能使用,本文主要SpringBoot通過(guò)DevTools實(shí)現(xiàn)熱部署,感興趣的朋友一起看看吧2023-11-11