Spring 事物 @Transactional 常見坑點

聊起Spring aop很多人肯定都覺得自己使用的很熟練,比如日誌,事物等等,當我問起事物怎麼實現的時候,他們都會說加個註解@Transactional就可以了,而我再問你有沒想過這中間有坑的時候,都說不知道,甚至工作五六年的人都不知道。這些坑不是來自spring本身,而是來自使用者,因爲他們用的不熟且沒有驗證。最近,看見公司項目中就有人埋了坑而不自知,所以我決定記錄一下。之前已經寫過spring 事務作用於異步方法或線程池時有坑,今天說說其他的坑。

1.一個類內部方法間調用的時候,可能不生效,如圖:
在這裏插入圖片描述
注意,這裏只是可能會不生效,因爲如果insert()上加了@Transactional的話,結果就不一樣了。解決方案及證明如下:
在這裏插入圖片描述
SpringUtils代碼如下:

	@Component
	public class SpringUtils implements ApplicationContextAware {
    	private static ApplicationContext ac;

    	@Override
    	public void setApplicationContext(ApplicationContext applicationContext) throws 	BeansException {
            this.ac = applicationContext;
   	    }

    	public static ApplicationContext getAc() {
            return ac;
   	    }
    }

當然,也可以使用下面這種方式:

@Autowired
private ApplicationContext applicationContext;

StudentServiceImpl impl = applicationContext.getBean(StudentServiceImpl.class);

那麼,問題的根本是什麼呢?我們都知道aop是通過動態代理實現的,簡言之:@Transactional默認只能通過代理攔截調用,第一幅圖中直接調用insert2(),相當於this.insert2(),不是通過代理對象調用的,所以事務不生效,而通過從容器中獲取serviceImpl再調用insert2(),這時候就用上了代理對象,所以事務生效。
在這裏插入圖片描述
2. 當@Transactional作用於非public方法(如protected、private)時,事務不生效,如下圖:
在這裏插入圖片描述
其實,如果insert2()方法用private修飾時,開發工具甚至會有提示,但是很多人對這種提示視而不見,如下圖:
在這裏插入圖片描述
這個的解決方案其實很簡單,用public修飾就得了(spring官方也提出過其他解決方案)。至於原因,其實官網有過說法,截圖如下:
在這裏插入圖片描述
源碼中對此做出的處理在org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute中,如下圖:
在這裏插入圖片描述
3.需要回滾的異常和拋出的異常不匹配,不指定的情況下默認回滾RuntimeException。其實java中異常可以分爲受檢異常和非受檢異常,簡單來講,受檢異常就是你寫代碼的時候編譯器提示你需要拋出或者捕捉的異常,下面以拋出FileNotFoundException(不屬於RuntimeException),回滾RuntimeException爲例:
在這裏插入圖片描述
最終可以看到數據庫多了一條數據,這個問題解決起來比較容易,但可能也容易被忽略。

4.加了註解但異常被捕捉後並未拋出:今天神奇的發現有人在方法上加了註解,而方法體中對所有代碼進行了try catch且並沒有手動拋出,我不知道這位開發同學怎麼想的,他這樣做相當於沒有異常拋出,spring 事物無法感知到此處需要回滾事物。

很多時候,我發現開發人員覺得自己會用一個註解就覺得掌握了某個知識點,特別是像@Transactional這種被廣泛應用於項目中的,其實沒有深入瞭解一個知識點沒什麼,因爲一個人不可能掌握那麼多知識,但是,這種問題的產生說明他們沒有對代碼進行過實際驗證,只要驗證就知道這些寫法都是有問題的。問題雖小,可是如果到生產上由於髒數據的產生而導致的問題往往需要花費很長時間才能解決,且可能造成經濟損失。註解雖好,且用且珍惜吧。。。

參考文檔: https://docs.spring.io/spring/docs/5.2.4.RELEASE/spring-framework-reference/data-access.html#transaction-declarative-annotations

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章