使用Spring事物時(shí)不生效的場(chǎng)景及解決方法
一.類(lèi)沒(méi)被Spring管理
如果我們的類(lèi)沒(méi)有被Spring管理,那么即使使用了Spring事物也不會(huì)生效,要讓Spring管理我們的類(lèi),需要標(biāo)注@Component,@Service等注解。
二.沒(méi)有標(biāo)注@Transactional注解的方法調(diào)用了標(biāo)注@Transactional注解的方法
如果一個(gè)方法沒(méi)有使用@Transactional注解,但是它去調(diào)用了帶@Transactional注解的方法,那么當(dāng)前方法的事物不生效。
public void saveUser(User user) throws Exception { save(user); } @Transactional(rollbackFor = Exception.class) public void save(User user) { try { userDao.save(user); exceptionMethod(); roleService.save(user.getRole()); } catch (Exception e) { throw new RuntimeException(e); } }
如上所示,saveUser方法調(diào)用了save方法,但是saveUser沒(méi)有標(biāo)@Transactional注解,而它調(diào)用了save方法,save方法標(biāo)了@Transactional,不過(guò)事物不會(huì)生效,這是因?yàn)榉椒](méi)被代理,直接是普通方法調(diào)用,所以事物自然不生效。
如果一個(gè)方法中調(diào)用了其他方法,需要在主方法上加@Transactional注解這個(gè)方法才能被代理,如下代碼,當(dāng)然,遠(yuǎn)程調(diào)用@Transactional就不生效了,就需要分布式事物了。
@Transactional(rollbackFor = Exception.class) public void saveAnnotation(User user) throws Exception { save(user); } public void save(User user) { try { userDao.save(user); exceptionMethod(); roleService.save(user.getRole()); } catch (Exception e) { throw new RuntimeException(e); } }
三.異常使用不正確
如果異常使用不當(dāng),那么事物也不會(huì)生效,這里的異常有兩種,一種是我們拋出的異常,一種是@Transactional注解所接受的異常。
1.如果我們?cè)诔绦虼a中自己捕獲了異常導(dǎo)致Spring事物捕獲不到異常,那么事物也不會(huì)生效,如下,exceptionMethod方法捕獲了異常并打印異常信息,那么異常并不會(huì)被Spring事物捕獲到,所以事物并不會(huì)回滾。
@Transactional(rollbackFor = Exception.class) public void saveAnnotation(User user) throws Exception { userDao.save(user); exceptionMethod(); roleService.save(user.getRole()); } private void exceptionMethod() throws Exception { try { int i = 1 / 0; } catch (Exception e) { e.printStackTrace(); } }
如果需要事物回滾,那么就需要將異常拋到saveAnnotation方法,這樣Spring事物才能感知到異常,從而進(jìn)行事物回滾。
2.@Transactional注解有一個(gè)屬性rollbackFor,它代表回滾的異常,也就是說(shuō)只有捕獲到這種異常事物才會(huì)回滾,它默認(rèn)的是RunTimeException。
@Transactional public void saveAnnotation(User user) throws Exception { userDao.save(user); exceptionMethod(); roleService.save(user.getRole()); } private void exceptionMethod() throws Exception { try { int i = 1 / 0; } catch (Exception e) { throw new Exception("拋出異常"); } }
如上代碼,exceptionMethod方法拋出了Exception異常,而@Transactional注解我們沒(méi)有指定rollbackFor,所以使用的是默認(rèn)的RunTimeException,所以事物不能回滾,如果我們需要事物回滾,需要讓rollbackFor指定的異常是拋出異常的父類(lèi)或者和自己一樣才行,如下所示。
@Transactional(rollbackFor = Exception.class) public void saveAnnotation(User user) { userDao.save(user); exceptionMethod(); roleService.save(user.getRole()); } private void exceptionMethod() { try { int i = 1 / 0; } catch (Exception e) { throw new ArithmeticException("運(yùn)算異常"); } }
四.不正確的傳播行為
如果傳播行為使用的是NOT_SUPPORTED
,那么事物無(wú)法回滾。NOT_SUPPORTED表示當(dāng)前方法不應(yīng)該有事務(wù),如果有事務(wù)存在,將它掛起,以無(wú)事務(wù)狀態(tài)運(yùn)行。
@Transactional(propagation = Propagation.NOT_SUPPORTED)
五.方法修飾為private
如果方法以private修飾,那么方法將不會(huì)被代理,事物自然不會(huì)生效,不過(guò)如果在進(jìn)行業(yè)務(wù)開(kāi)發(fā)的時(shí)候,對(duì)于需要其它類(lèi)進(jìn)行調(diào)用的方法,我們都是以public修飾,因?yàn)槿绻詐rivate修飾,其它類(lèi)想要訪問(wèn)的話需要借助反射才能訪問(wèn),在IDEA中,@Transactional方法如果修飾為private,會(huì)有錯(cuò)誤提醒,但是運(yùn)行不會(huì)報(bào)錯(cuò)。
不過(guò)一些場(chǎng)景我們可能需要反射調(diào)用,所以不應(yīng)該避開(kāi)這個(gè)問(wèn)題,還是將其修飾為public。
六.數(shù)據(jù)庫(kù)不支持事物
如果數(shù)據(jù)庫(kù)不支持事物,那么即使項(xiàng)目中使用了Spring事物,也不會(huì)生效,因?yàn)镾pring的事物最終也是JDBC的事物,JDBC事物也要數(shù)據(jù)庫(kù)支持事物才行,MySQL中MyISAM存儲(chǔ)引擎不支持事物,InnoDB才支持事物。
七.沒(méi)有配置事務(wù)管理器,導(dǎo)致事務(wù)失效
使用非SpringBoot項(xiàng)目,需要配置PlatformTransactionManager,需要加上@EnableTransactionManagement注解,如果是SpringBoot項(xiàng)目,那么可以不用配置,因?yàn)镾pringBoot默認(rèn)幫我們裝配好了,我們直接使用就好。
以上就是使用Spring事物時(shí)不生效的場(chǎng)景及解決方法的詳細(xì)內(nèi)容,更多關(guān)于使用Spring事物時(shí)不生效的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java super關(guān)鍵字用法實(shí)戰(zhàn)案例分析
這篇文章主要介紹了Java super關(guān)鍵字用法,結(jié)合具體案例形式分析了java super關(guān)鍵字調(diào)用父類(lèi)構(gòu)造方法、屬性及方法等相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2019-09-09Spring超出最大會(huì)話數(shù)(Max?sessions?limit?reached:?10000)
在Spring系統(tǒng)中遇到的Maxsessionslimitreached:10000錯(cuò)誤,該錯(cuò)誤由于會(huì)話數(shù)超過(guò)默認(rèn)限制10000而觸發(fā),下面就來(lái)介紹一下解決方法,感興趣的可以了解一下2024-12-12基于JWT的spring boot權(quán)限驗(yàn)證技術(shù)實(shí)現(xiàn)教程
這篇文章主要給大家介紹了關(guān)于基于JWT的spring boot權(quán)限驗(yàn)證技術(shù)實(shí)現(xiàn)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Java?將HTML轉(zhuǎn)為XML的詳細(xì)步驟
這篇文章主要介紹了Java?將HTML轉(zhuǎn)為XML,本文將以html轉(zhuǎn)為xml格式為例,介紹如何實(shí)現(xiàn)轉(zhuǎn)換,以下是詳細(xì)方法及步驟,需要的朋友可以參考下2022-06-06Intelli IDEA安裝Scala插件并安裝Scala軟件和配置環(huán)境變量的詳細(xì)教程
這篇文章主要介紹了Intelli IDEA安裝Scala插件并安裝Scala軟件和配置環(huán)境變量的詳細(xì)教程,需要的朋友可以參考下2020-10-10SpringCloud可視化鏈路追蹤系統(tǒng)Zipkin部署過(guò)程
這篇文章主要介紹了SpringCloud可視化鏈路追蹤系統(tǒng)Zipkin部署過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03基于SpringBoot實(shí)現(xiàn)上傳2種方法工程代碼實(shí)例
這篇文章主要介紹了基于SpringBoot實(shí)現(xiàn)上傳工程代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08詳解Java中的checked異常和unchecked異常區(qū)別
這篇文章主要介紹了詳解Java中的checked異常和unchecked異常區(qū)別,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02