從Spring源碼解析事務失效的原因
一、前言
1.Bean是否是代理對象
2.入口函數是否是public的
3.數據庫是否支持事務(Mysql的Mvlsam不支持事務),行鎖才支持事務
4.切點是否配置正確
5.內部方法間調用導致事務失效
因為this不是代理對象,可以配置 expose-proxy="true",就可以通過AopContext.currentProxy()獲取到當前類的代理對象。
<! -- expose-proxy="true”類內部可以獲取到當前類的代理對象--><aop: aspectj-autoproxy expose-proxy="true" /> @Enab1eAspect3AutoProxy(exposeProxy = true)
也可以注入當前bean
6.異常類型是否配置正確
默認只支持RuntimeException和Error,不支持檢查異常
想要支持檢查異常需要配置rollbackFor
@Transactional(rollbackFor = Exception.class)
7.異常被catch住了
代碼中手動catch了異常,然后又未拋出來,此時事務就不生效了。
二、方法不是 public 的
以下來自Spring官方文檔
大概意思就是 @Transactional 只能用于 public 的方法上,否則事務不會失效,如果要用在非 public 方法上,可以開啟 AspectJ 代理模式。
TransactionInterceptor#invoke
TransactionAspectSupport#invokeWithinTransaction
AbstractFallbackTransactionAttributeSource#getTransactionAttribute
AbstractFallbackTransactionAttributeSource#computeTransactionAttribute
allowPublicMethodsOnly方法由子類AnnotationTransactionAttributeSource實現,該子類方法中默認是true,所以當你加了事務注解的方法不是public時,該方法直接返回null
以上只說明 在spring的事務管理中存在這樣一個 public的判斷,至于后邊為啥由于這個判斷導致沒有織入事務,并沒有說明;
public導致失效原因
三、內部方法間調用導致事務失效
因為spring聲明式事務是基于AOP實現的,是使用動態(tài)代理來達到事務管理的目的,當前類調用的方法上面加@Transactional 這個是沒有任何作用的,因為調用這個方法的是this,沒有經過 Spring 的代理類。
解決方案一:
再聲明一個service,自己注入自己,將內部調用改為外部調用
解決方案二:
解決方案三:
使用編程式事務
四、異常類型是否配置正確
拋出RuntimeException異常,事務生效
拋出Exception異常,事務不生效
我們看下TransactionInterceptor類
TransactionInterceptor#invoke
TransactionAspectSupport#invokeWithinTransaction
TransactionAspectSupport#completeTransactionAfterThrowing
配置了這個,Exception異常的事務,就會生效
五、異常被catch住
代碼中手動catch了異常,然后又未拋出來,此時事務就不生效了。
解決方法:要么不catch需要回滾的異常,要么catch之后再拋出,要么手動回滾
解決方案一:
catch之后往外拋異常
解決方案二:
catch之后,設置手動回滾
到此這篇關于從Spring源碼解析事務失效的原因的文章就介紹到這了,更多相關Spring事務失效內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
mybatis plus表的創(chuàng)建時間和修改時間的操作方法
這篇文章主要介紹了mybatis plus表的創(chuàng)建時間和修改時間的實現方法,本文給大家分享兩種方法,每種方法通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2021-09-09