欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot中事務(wù)失效的六個原因解析

 更新時(shí)間:2023年10月19日 09:27:03   作者:yfs1024  
這篇文章主要介紹了SpringBoot中事務(wù)失效的六個原因解析,由于Spring的事務(wù)是基于AOP的方式結(jié)合動態(tài)代理來實(shí)現(xiàn)的,因此事務(wù)方法一定要是public的,這樣才能便于被Spring做事務(wù)的代理和增強(qiáng),需要的朋友可以參考下

SpringBoot中事務(wù)失效的原因

常見的事務(wù)失效原因包括如下六個:

1. 事務(wù)方法非public修飾

由于Spring的事務(wù)是基于AOP的方式結(jié)合動態(tài)代理來實(shí)現(xiàn)的。因此事務(wù)方法一定要是public的,這樣才能便于被Spring做事務(wù)的代理和增強(qiáng)。

而且,在Spring內(nèi)部也會有一個 org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource類,去檢查事務(wù)方法的修飾符:

@Nullable
 protected TransactionAttribute computeTransactionAttribute(
  Method method, @Nullable Class<?> targetClass) {
   // Don't allow non-public methods, as configured.
   if (allowPublicMethodsOnly() && 
  !Modifier.isPublic(method.getModifiers())) {
      return null;
   }

    // ... 略

   return null;
 }

2. 非事務(wù)方法調(diào)用事務(wù)方法

@Service
public class OrderService {
    
    public void createOrder(){
        // ... 準(zhǔn)備訂單數(shù)據(jù)
        
        // 生成訂單并扣減庫存
        insertOrderAndReduceStock();
    }
    
    @Transactional
    public void insertOrderAndReduceStock(){
        // 生成訂單
        insertOrder();
        // 扣減庫存
        reduceStock();
    }
}

可以看到,insertOrderAndReduceStock方法是一個事務(wù)方法,肯定會被Spring事務(wù)管理。Spring會給OrderService類生成一個動態(tài)代理對象,對insertOrderAndReduceStock方法做增加,實(shí)現(xiàn)事務(wù)效果。

但是現(xiàn)在createOrder方法是一個非事務(wù)方法,在其中調(diào)用了insertOrderAndReduceStock方法,這個調(diào)用其實(shí)隱含了一個this.的前綴。也就是說,這里相當(dāng)于是直接調(diào)用原始的OrderService中的普通方法,而非被Spring代理對象的代理方法。那事務(wù)肯定就失效了!

3. 事務(wù)方法的異常被捕獲了

異常被捕獲了但是沒有往外拋異常,所以事務(wù)沒有發(fā)現(xiàn)方法中出現(xiàn)錯誤,所以也就沒有回滾

 @Transactional
    public void createOrder(){
        // ... 準(zhǔn)備訂單數(shù)據(jù)
        // 生成訂單
        insertOrder();
        // 扣減庫存
        reduceStock();
    }

    private void reduceStock() {
        try {
            // ...扣庫存
        } catch (Exception e) {
            // 處理異常
        }
    }

在這段代碼中,reduceStock方法內(nèi)部直接捕獲了Exception類型的異常,也就是說方法執(zhí)行過程中即便出現(xiàn)了異常也不會向外拋出。

而Spring的事務(wù)管理就是要感知業(yè)務(wù)方法的異常,當(dāng)捕獲到異常后才會回滾事務(wù)。

現(xiàn)在事務(wù)被捕獲,就會導(dǎo)致Spring無法感知事務(wù)異常,自然不會回滾,事務(wù)就失效了。

4. 事務(wù)異常類型不對

@Transactional(rollbackFor = RuntimeException.class)
public void createOrder() throws IOException {
    // ... 準(zhǔn)備訂單數(shù)據(jù)

    // 生成訂單
    insertOrder();
    // 扣減庫存
    reduceStock();

    throw new IOException();
}

Spring的事務(wù)管理默認(rèn)感知的異常類型是RuntimeException,當(dāng)事務(wù)方法內(nèi)部拋出了一個IOException時(shí),不會被Spring捕獲,因此就不會觸發(fā)事務(wù)回滾,事務(wù)就失效了。

因此,當(dāng)我們的業(yè)務(wù)中會拋出RuntimeException以外的異常時(shí),應(yīng)該通過@Transactional注解中的rollbackFor屬性來指定異常類型:

@Transactional(rollbackFor = Exception.class)

5.事務(wù)傳播行為不對

    @Transactional
    public void createOrder(){
        // 生成訂單
        insertOrder();
        // 扣減庫存
        reduceStock();
        throw new RuntimeException("業(yè)務(wù)異常");
    }

	@Transactional  // 默認(rèn)的是如果當(dāng)前沒有事務(wù),自己創(chuàng)建事務(wù),如果有事務(wù)則加入
    public void insertOrder() {
    
    }
	// 不管當(dāng)前方法所在方法有沒有都開啟一個事務(wù)
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void reduceStock() {
        
    }

在示例代碼中,事務(wù)的入口是createOrder()方法,會開啟一個事務(wù),可以成為外部事務(wù)。在createOrder()方法內(nèi)部又調(diào)用了insertOrder()方法和reduceStock()方法。這兩個都是事務(wù)方法。

不過,reduceStock()方法的事務(wù)傳播行為是REQUIRES_NEW,這會導(dǎo)致在進(jìn)入reduceStock()方法時(shí)會創(chuàng)建一個新的事務(wù),可以成為子事務(wù)。insertOrder()則是默認(rèn),因此會與createOrder()合并事務(wù)。

因此,當(dāng)createOrder方法最后拋出異常時(shí),只會導(dǎo)致insertOrder方法回滾,而不會導(dǎo)致reduceStock方法回滾,因?yàn)閞educeStock是一個獨(dú)立事務(wù)。

所以,一定要慎用傳播行為,注意外部事務(wù)與內(nèi)部事務(wù)之間的關(guān)系。

6.沒有被Spring管理

即當(dāng)前類沒有被SpringBoot掃描

第二種事務(wù)失效的解決方案:

上面的問題在于非事務(wù)方法中調(diào)用事務(wù)方法其中隱含了一個this.的前綴, 雖然當(dāng)前方法的事務(wù)也被代理類生成了,但是因?yàn)槟J(rèn)關(guān)鍵字的原因,調(diào)用的還是原來的是沒有事務(wù)的方法.

所以我們現(xiàn)在要做的就是要找到被代理之后的類,然后再在方法中調(diào)用該方法

1)引入AspectJ依賴:

<!--aspecj-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
	<version>1.9.7</version>
</dependency>

2)暴露代理對象

在啟動類上添加注解,暴露代理對象:

3)使用代理對象

通過AopContext拿到當(dāng)前類的代理對象,然后調(diào)用對應(yīng)方法

// 返回值是Object
IUserCouponService userCouponService = (IUserCouponService) AopContext.currentProxy();
userCouponService.insertCouponAndCheck(userId, coupon, null);

(補(bǔ)充 )StringBoot中事務(wù)相關(guān)的接口

在Spring中有兩個和事務(wù)相關(guān)的接口

PlatformTransactionManager 平臺事務(wù)管理接口

作用; 對于不同的數(shù)據(jù)源采用不同的管理平臺, 常用的實(shí)現(xiàn)類如下

  • DataSourceTransactionManager:使用JDBC或MyBatis進(jìn)行事務(wù)管理。適用于DataSource數(shù)據(jù)源。
  • HibernateTransactionManager:使用Hibernate進(jìn)行事務(wù)管理。適用于Hibernate持久層框架。

TransactionDefinition 事務(wù)定義接口

TransactionDefinition 接口中定義了事務(wù)的描述相關(guān)的三類常量:

  • 事務(wù)隔離級別
  • 事務(wù)傳播行為
  • 事務(wù)默認(rèn)超時(shí)時(shí)限

1. 事務(wù)隔離級別

  • DEFAULT : 采用DB默認(rèn)的事務(wù)隔離級別.mysql中默認(rèn)的是 REPEATABLE_READ (repeatable_read)
  • READ_UNCOMMITTED: 讀未提交 未解決任何并發(fā)問題
  • READ_COMMITTED: 讀已提交 解決了臟讀,存在不可重復(fù)讀和幻讀
  • REPETABLE_READ : 可重復(fù)讀,解決了臟讀,不可重復(fù)讀,存在幻讀
  • SERIALIZABLE :串行化.不存在并發(fā)問題

那么什么是臟讀, 幻讀和 不可重復(fù)讀呢?

臟讀(dirty read): 當(dāng)一個事務(wù)讀取另一個事務(wù)尚未提交的修改時(shí),產(chǎn)生臟讀

不可重復(fù)讀(nonrepeatable read):同一查詢在同一事務(wù)中多次進(jìn)行,由于其他提交事務(wù)所做的修改或刪除,每次返回不同的結(jié)果集,此時(shí)發(fā)生不可重復(fù)讀

幻讀(phantom read):同一查詢在同一事務(wù)中多次進(jìn)行,由于其他提交事務(wù)所做的插入操作,每次返回不同的結(jié)果集,此時(shí)發(fā)生幻讀

2. 事務(wù)的傳播行為

定義了七個事務(wù)的傳播行為:都是以 PROPAGATION_開頭 propagation(常用三個)

事務(wù)傳播行為是指,處于不同事務(wù)中的方法在相互調(diào)用時(shí),執(zhí)行期間事務(wù)的維護(hù)情況

  • propagation_required (spring默認(rèn)的傳播行為)
  • propagation_requires_new
  • propagation_supports

propagation_required :

說明:指定的方法必須在事務(wù)內(nèi)執(zhí)行。若當(dāng)前存在事務(wù),就加入到當(dāng)前事務(wù)中;若當(dāng)前沒有事務(wù),則創(chuàng)建一個新事務(wù)。這種傳播行為是最常見的選擇,也是 Spring 默認(rèn)的事務(wù)傳播行為。 

演示說明:

**如該傳播行為加在doOther()**方法上。若 doSome()方法在調(diào)用 doOther()方法時(shí)就是在事務(wù)內(nèi)運(yùn)行的,則 doOther()方法的執(zhí)行也加入到該事務(wù)內(nèi)執(zhí)行。若 doSome()方法在調(diào)用 doOther()方法時(shí)沒有在事務(wù)內(nèi)執(zhí)行,則 doOther()方法會創(chuàng)建一個事務(wù),并在其中執(zhí)行。

propagation_requires_new:

說明:總是新建一個事務(wù),如當(dāng)前存在事務(wù),就將當(dāng)前事務(wù)掛起,直到新事務(wù)執(zhí)行完畢

propagation_supports:

說明:指定的方法支持當(dāng)前事務(wù),但若當(dāng)前沒有事務(wù),也可以以非事務(wù)方法執(zhí)行

3. 事務(wù)超時(shí)時(shí)限

該值一般就是用默認(rèn)值

到此這篇關(guān)于SpringBoot中事務(wù)失效的六個原因解析的文章就介紹到這了,更多相關(guān)SpringBoot事務(wù)失效原因內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring中容器的創(chuàng)建流程詳細(xì)解讀

    Spring中容器的創(chuàng)建流程詳細(xì)解讀

    這篇文章主要介紹了Spring中容器的創(chuàng)建流程詳細(xì)解讀,Spring?框架其本質(zhì)是作為一個容器,提供給應(yīng)用程序需要的對象,了解容器的誕生過程,有助于我們理解?Spring?框架,也便于我們“插手”這個過程,需要的朋友可以參考下
    2023-10-10
  • Java中StringBuilder常用構(gòu)造方法解析

    Java中StringBuilder常用構(gòu)造方法解析

    這篇文章主要介紹了Java中StringBuilder常用構(gòu)造方法解析,StringBuilder是一個可標(biāo)的字符串類,我們可以吧它看成是一個容器這里的可變指的是StringBuilder對象中的內(nèi)容是可變的,需要的朋友可以參考下
    2024-01-01
  • Mybatis中的高級映射一對一、一對多、多對多

    Mybatis中的高級映射一對一、一對多、多對多

    這篇文章主要介紹了Mybatis中的高級映射一對一、一對多、多對多的相關(guān)資料,需要的朋友可以參考下
    2016-08-08
  • Spring 項(xiàng)目常用pom文件的依賴

    Spring 項(xiàng)目常用pom文件的依賴

    這篇文章主要介紹了Spring 項(xiàng)目常用pom文件的依賴,文中給大家提到了Spring boot starter pom的依賴關(guān)系說明,需要的朋友參考下吧
    2018-03-03
  • Springboot實(shí)現(xiàn)對配置文件中的明文密碼加密詳解

    Springboot實(shí)現(xiàn)對配置文件中的明文密碼加密詳解

    我們在SpringBoot項(xiàng)目當(dāng)中,會把數(shù)據(jù)庫的用戶名密碼等配置直接放在yaml或者properties文件中,這樣維護(hù)數(shù)據(jù)庫的密碼等敏感信息顯然是有一定風(fēng)險(xiǎn)的。所以本文為大家整理了對配置文件中的明文密碼加密的方法,希望對大家有所幫助
    2023-03-03
  • java中為什么要謹(jǐn)慎使用Arrays.asList、ArrayList的subList

    java中為什么要謹(jǐn)慎使用Arrays.asList、ArrayList的subList

    這篇文章主要介紹了java中為什么要謹(jǐn)慎使用Arrays.asList、ArrayList的subList,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • java泛型基本知識和通用方法

    java泛型基本知識和通用方法

    這篇文章主要介紹了java泛型基礎(chǔ)知識及通用方法,從以下幾個方面介紹一下java的泛型: 基礎(chǔ), 泛型關(guān)鍵字, 泛型方法, 泛型類和接口,感興趣的可以了解一下
    2021-06-06
  • java高效讀大文件(csv,text)的幾種處理方式

    java高效讀大文件(csv,text)的幾種處理方式

    這篇文章主要給大家介紹了關(guān)于java高效讀大文件(csv,text)的幾種處理方式,Java中處理大文件時(shí),通常需要采取一些特定的策略來避免內(nèi)存溢出或性能問題,文中通過代碼及圖片介紹的非常詳細(xì),需要的朋友可以參考下
    2024-07-07
  • Java垃圾回收之標(biāo)記清除算法詳解

    Java垃圾回收之標(biāo)記清除算法詳解

    今天小編就為大家分享一篇關(guān)于Java垃圾回收之標(biāo)記清除算法詳解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • Java多線程中的ThreadLocal應(yīng)用場景及問題解讀

    Java多線程中的ThreadLocal應(yīng)用場景及問題解讀

    這篇文章主要介紹了Java多線程中的ThreadLocal應(yīng)用場景及問題解讀,ThreadLocal這個類在多線程并發(fā)中主要的使用場景是什么呢,我們都知道多線程并發(fā)問題實(shí)際就是多個線程對公共資源訪問和修改問題,需要的朋友可以參考下
    2023-12-12

最新評論