這算是spring事務第9篇文章了,花了這么多篇文章介紹事務這塊的知識,說明事務這塊的東西確實比較多、知識點比較細,也非常重要,希望大家能夠重視起來,吃透這塊的知識。
本文2個目的:
1、使用spring事務的過程中,哪些情況會導致事務失效?
2、遇到事務相關bug時,有哪些方法可以快速定位bug?
3、文末有福利
1、事務失效的7種情況
- 未啟用spring事務管理功能
- 方法不是public類型的
- 數據源未配置事務管理器
- 自身調用問題
- 異常類型錯誤
- 異常被吞了
- 業務和spring事務代碼必須在一個線程中
1.1、未啟用spring事務管理功能
@EnableTransactionManagement 注解用來啟用spring事務自動管理事務的功能,這個注解千萬不要忘記寫了。
1.2、方法不是public類型的
@Transaction 可以用在類上、接口上、public方法上,如果將@Trasaction用在了非public方法上,事務將無效。
1.3、數據源未配置事務管理器
spring是通過事務管理器了來管理事務的,一定不要忘記配置事務管理器了,要注意為每個數據源配置一個事務管理器:
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
1.4、自身調用問題
spring是通過aop的方式,對需要spring管理事務的bean生成了代理對象,然后通過代理對象攔截了目標方法的執行,在方法前后添加了事務的功能,所以必須通過代理對象調用目標方法的時候,事務才會起效。
看下面代碼,大家思考一個問題:當外部直接調用m1的時候,m2方法的事務會生效么?
@Component public class UserService { public void m1(){ this.m2(); } @Transactional public void m2(){ //執行db操作 } }
顯然不會生效,因為m1中通過this的方式調用了m2方法,而this並不是代理對象,this.m2()不會被事務攔截器,所以事務是無效的,如果外部直接調用通過UserService這個bean來調用m2方法,事務是有效的,上面代碼可以做一下調整,如下,@1在UserService中注入了自己,此時m1中的m2事務是生效的
@Component public class UserService { @Autowired //@1 private UserService userService; public void m1() { this.userService.m2(); } @Transactional public void m2() { //執行db操作 } }
重點:必須通過代理對象訪問方法,事務才會生效。
1.5、異常類型錯誤
spring事務回滾的機制:對業務方法進行try catch,當捕獲到有指定的異常時,spring自動對事務進行回滾,那么問題來了,哪些異常spring會回滾事務呢?
並不是任何異常情況下,spring都會回滾事務,默認情況下,RuntimeException和Error的情況下,spring事務才會回滾。
也可以自定義回滾的異常類型:
@Transactional(rollbackFor = {異常類型列表})
1.6、異常被吞了
當業務方法拋出異常,spring感知到異常的時候,才會做事務回滾的操作,若方法內部將異常給吞了,那么事務無法感知到異常了,事務就不會回滾了。
如下代碼,事務操作2發生了異常,但是被捕獲了,此時事務並不會被回滾
@Transactional public void m1(){ 事務操作1 try{ 事務操作2,內部拋出了異常 }catch(Exception e){ } }
1.7、業務和spring事務代碼必須在一個線程中
spring事務實現中使用了ThreadLocal,ThreadLocal大家應該知道吧,可以實現同一個線程中數據共享,必須是同一個線程的時候,數據才可以共享,這就要求業務代碼必須和spring事務的源碼執行過程必須在一個線程中,才會受spring事務的控制,比如下面代碼,方法內部的子線程內部執行的事務操作將不受m1方法上spring事務的控制,這個大家一定要注意
@Transactional public void m1() { new Thread() { 一系列事務操作 }.start(); }
2、如何快速定位事務相關bug?
2種方式
方式1:看日志
如果你使用了logback或者log4j來輸出日志,可以修改一下日志級別為debug模式,可以看到事務的詳細執行日志,幫助你定位錯誤
方式2:調試代碼
如果你對源碼比較了解,那么你會知道被spring管理事務的業務方法,執行的時候都會被TransactionInterceptor攔截器攔截,會進入到它的invoke方法中,咱們可以在invoke方法中設置一些斷點,可以看到詳細的執行過程,排錯也就比較容易了。
整體上來說,還是需要你深入理解原理,原理了解了,寫代碼的時候本身就會避免很多坑。
來源:https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648937999&idx=2&sn=e356cb09e596c6c9af4219e7da40ee75&scene=21#wechat_redirect