spring成神之路第五十一篇:導致 Spring 事務失效常見的幾種情況


這算是spring事務第9篇文章了,花了這么多篇文章介紹事務這塊的知識,說明事務這塊的東西確實比較多、知識點比較細,也非常重要,希望大家能夠重視起來,吃透這塊的知識。

本文2個目的:

1、使用spring事務的過程中,哪些情況會導致事務失效?

2、遇到事務相關bug時,有哪些方法可以快速定位bug?

3、文末有福利

1、事務失效的7種情況

  1. 未啟用spring事務管理功能
  2. 方法不是public類型的
  3. 數據源未配置事務管理器
  4. 自身調用問題
  5. 異常類型錯誤
  6. 異常被吞了
  7. 業務和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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM