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

Spring事務(wù)失效的各種場景(13種)

 更新時間:2022年07月20日 10:23:41   作者:Daylight629  
本文主要介紹了Spring事務(wù)失效的各種場景,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、訪問權(quán)限

Java的訪問權(quán)限主要是:private、default、protected、public,它們的權(quán)限則是依次變大。
如果我們在開發(fā)的時候定義錯誤的訪問權(quán)限,就會導(dǎo)致事務(wù)出現(xiàn)問題

@Service
public class DemoService {
    
    @Transactional
    private void query(Demo demo) {

    }
}

我們可以查看源碼,可以明白,spring事務(wù)的實現(xiàn)AbstractFallbackTransactionAttributeSource類的computeTransactionAttribute方法中有個判斷,如果目標(biāo)方法不是public,則TransactionAttribute返回null,即不支持事務(wù)。

二、方法用final修飾

我們在學(xué)習(xí)的時候都知道,某個方法不想被子類繼承的時候就會加上關(guān)鍵字final,這種寫法正常來說是沒有問題的,但是如果該方法被用上事務(wù)就不行了

@Service
public class DemoService {

    @Transactional
    public final void query(Demo demo) {
      
    }
}

這樣的話會導(dǎo)致事務(wù)的失效,因為spring事務(wù)底層實現(xiàn)使用了代理,aop,通過jdk的動態(tài)代理或者cglib,生成了代理類,在代理類中實現(xiàn)了事務(wù)功能,如果方法被final修飾,無法重寫該方法,也就無法添加事務(wù)的功能了

像idea這里就提出了提示,同樣的如果方法是static方法也是不行的

因為靜態(tài)方法是屬于類的,而不是屬于對象的,無法重寫靜態(tài)方法所以也就不可能實現(xiàn)事務(wù)

三、方法內(nèi)部調(diào)用

在同一個類的service中,調(diào)用其他的事務(wù)方法

@Service
public class DemoService {

    @Transactional
    public  void query(Demo demo) {
        save(demo);
    }
    
    @Transactional
    public void save(Demo demo) {
        
    }
    
}

可以看到,query方法調(diào)用了save的方法,由于spring的事務(wù)實現(xiàn)是因為aop生成代理,這樣是直接調(diào)用了this對象,所以也不會生成事務(wù)。

解決方法:
1、增加一個service,把一個事務(wù)的方法移到新增加的service方法里面,然后進行注入再調(diào)用

@Service
public class DemoTwoService {
    
    @Transactional
    public void save(Demo demo) {

    }
}

@Service
public class DemoService {

    @Autowired
    DemoTwoService demoTwoService;

    @Transactional
    public  void query(Demo demo) {
        demoTwoService.save(demo);
    }
}

2、在自己類中注入自己

@Service
public class DemoService {

    @Autowired
    DemoService demoService;

    @Transactional
    public  void query(Demo demo) {
        demoService.save(demo);
    }

    @Transactional
    public void save(Demo demo) {

    }
}

由于這種寫法基于spring的三級緩存不會導(dǎo)致,循環(huán)依賴的問題出現(xiàn)

3、通過AopContentent

@Service
public class DemoService {
    
    @Transactional
    public  void query(Demo demo) {
        DemoService demoService = (DemoService)AopContext.currentProxy();
        demoService.save(demo);
    }

    @Transactional
    public void save(Demo demo) {

    }
}

四、沒有被spring管理

在使用spring事務(wù)的時候,對象要被spring進行管理,也就是需要創(chuàng)建bean,一般我們都會加@Controller、@Service、@Component、@Repository等注解,可以自動實現(xiàn)bean實例化和依賴注入的功能。,如果忘記加了,也會導(dǎo)致,事務(wù)的失效

五、多線程調(diào)用

@Service
public class DemoService {

    @Autowired
    DemoTwoService demoTwoService;

    @Transactional
    public  void query(Demo demo) {
        new Thread(()->{
            demoTwoService.save(demo);
        }).start();
    }
}

通過上面的例子,我們可以知道,query調(diào)用了事務(wù)方法save,但是事務(wù)方法在另一個線程里面調(diào)用,這樣會導(dǎo)致兩個方法在不同的一個線程中,獲取的數(shù)據(jù)庫連接也不一樣,所以會是兩個不同的事務(wù),如果save的方法拋出了異常,query回滾是不可能的,看過spring源碼,我們可以知道,spring的事務(wù)是通過連接數(shù)據(jù)庫來實現(xiàn)的,當(dāng)前線程保存了一個map,key—數(shù)據(jù)源,value----數(shù)據(jù)庫連接,事務(wù)其實就是指向同一個連接的,只有擁有同一個數(shù)據(jù)庫連接才能同時提交和回滾,如果在不同的線程,數(shù)據(jù)庫的連接不是同一個,所以事務(wù)也不是同一個。

private static final ThreadLocal<Map<Object, Object>> resources =

  new NamedThreadLocal<>("Transactional resources");

六、設(shè)計的表不支持事務(wù)

我們都知道,mysql5之前默認(rèn)的數(shù)據(jù)庫引擎是MyISAM,可能一些老的項目還在使用,但是他是不支持事務(wù)的

七、沒有開啟事務(wù)

如果創(chuàng)建的不是springboot項目可能會導(dǎo)致這樣的問題出現(xiàn),因為springboot項目有自動裝配的類DataSourceTransactionManagerAutoConfiguration,已經(jīng)默認(rèn)開啟了事務(wù),配置spring.datasource參數(shù)就行,如果是spring項目,需要在applicationContext.xml配置的,不然事務(wù)不會生效

<!-- 配置事務(wù)管理器 --> 
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager"> 
    <property name="dataSource" ref="dataSource"></property> 
</bean> 
<tx:advice id="advice" transaction-manager="transactionManager"> 
    <tx:attributes> 
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes> 
</tx:advice> 
<!-- 用切點把事務(wù)切進去 --> 
<aop:config> 
    <aop:pointcut expression="execution(* com.demo.*.*(..))" id="pointcut"/> 
    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/> 
</aop:config> 

還有就是切點配錯,也會導(dǎo)致事務(wù)失效

八、錯誤的事務(wù)傳播

我們在使用@Transactional注解時,是可以指定propagation參數(shù)的。
該參數(shù)的作用是指定事務(wù)的傳播特性,
spring目前支持7種傳播特性:

  • REQUIRED 如果當(dāng)前上下文中存在事務(wù),那么加入該事務(wù),如果不存在事務(wù),創(chuàng)建一個事務(wù),這是默認(rèn)的傳播屬性值。
  • SUPPORTS 如果當(dāng)前上下文存在事務(wù),則支持事務(wù)加入事務(wù),如果不存在事務(wù),則使用非事務(wù)的方式執(zhí)行。
  • MANDATORY 如果當(dāng)前上下文中存在事務(wù),否則拋出異常。
  • REQUIRES_NEW 每次都會新建一個事務(wù),并且同時將上下文中的事務(wù)掛起,執(zhí)行當(dāng)前新建事務(wù)完成以后,上下文事務(wù)恢復(fù)再執(zhí)行。
  • NOT_SUPPORTED 如果當(dāng)前上下文中存在事務(wù),則掛起當(dāng)前事務(wù),然后新的方法在沒有事務(wù)的環(huán)境中執(zhí)行。
  • NEVER 如果當(dāng)前上下文中存在事務(wù),則拋出異常,否則在無事務(wù)環(huán)境上執(zhí)行代碼。
  • NESTED 如果當(dāng)前上下文中存在事務(wù),則嵌套事務(wù)執(zhí)行,如果不存在事務(wù),則新建事務(wù)。

如果我們在手動設(shè)置propagation參數(shù)的時候,把傳播特性設(shè)置錯了

@Service
public class DemoService {

    @Transactional(propagation = Propagation.NEVER)
    public  void query(Demo demo) {

    }
}

我們可以看到query的事務(wù)傳播設(shè)置為了Propagation.NEVER,這種類型的傳播不支持事務(wù),會拋異常,
目前支持事務(wù)的三種傳播特性為:REQUIRED,REQUIRES_NEW,NESTED

九、自己捕獲了異常

事務(wù)不回滾,可能是我們在寫代碼的時候自己在代碼手動進行了try…catch

@Transactional
    public  void query(Demo demo) {
        try {
            save(demo);
        } catch (Exception e) {
            System.out.println("異常");
        }
    }

這種情況下,spring事務(wù)不會進行回滾,因為我們進行了手動捕獲異常,然后沒有手動拋出,如果想要spring事務(wù)的正?;貪L,必須拋出它能處理的異常,如果沒有拋出異常,spring會認(rèn)為程序沒有問題。

十、手動拋出別的異常

我們沒有手動捕獲異常,但是如果拋出的異常不正確,spring事務(wù)也不會回滾。

 @Transactional
    public  void query(Demo demo) throws Exception{
        try {
            save(demo);
        } catch (Exception e) {
            throw new Exception(e);
        }
    }

上面我們捕獲了異常,然后手動拋出Exception,事務(wù)同樣不會回滾,因為spring事務(wù),默認(rèn)情況下不會回滾Exception(非運行時的異常),只會回滾RuntimeException(運行時異常)和Error(錯誤)。

十一、自定義回滾異常

在使用@Transactional注解聲明事務(wù)時,有時我們想自定義回滾的異常,spring也是支持的。可以通過設(shè)置rollbackFor參數(shù),來完成這個功能。

但如果這個參數(shù)的值設(shè)置錯了,就會引出一些問題

  @Transactional(rollbackFor = BusinessException.class)
    public  void query(Demo demo) throws Exception{
            save(demo);
    }

上面是我們自定義的業(yè)務(wù)異常,如果在執(zhí)行上面這段代碼,保存和更新數(shù)據(jù)時,程序報錯了,拋了SqlException、DuplicateKeyException等異常。而BusinessException是我們自定義的異常,報錯的異常不屬于BusinessException,所以事務(wù)也不會回滾。即使rollbackFor有默認(rèn)值,但阿里巴巴開發(fā)者規(guī)范中,還是要求開發(fā)者重新指定該參數(shù)。
因為如果使用默認(rèn)值,一旦程序拋出了Exception,事務(wù)不會回滾,這會出現(xiàn)很大的bug。所以,建議一般情況下,將該參數(shù)設(shè)置成:Exception或Throwable。

十二、嵌套事務(wù)回滾過頭

@Service
public class DemoService {

    @Autowired
    private DemoTwoService demoTwoService;

    @Autowired
    private DemoDao demoDao;
    public
    @Transactional(rollbackFor = Exception.class)
    public  void query(Demo demo) throws Exception{
        demoDao.save(demo);
        demoTwoService.save(demo);
    }
}

原本只是希望回滾demoServise.save(),不回滾demoDao.save(demo);,但是這種情況兩個都會被回滾,因為demoTwoService.save(demo);沒有捕獲異常,往上拋出,導(dǎo)致query進行回滾,所以同時回滾了兩個
解決方法:

@Service
public class DemoService {

    @Autowired
    private DemoTwoService demoTwoService;

    @Autowired
    private DemoDao demoDao;
    public
    @Transactional(rollbackFor = Exception.class)
    public  void query(Demo demo) throws Exception{
        demoDao.save(demo);
        try {
            demoTwoService.save(demo);
        } finally {
            
        }
    }
}

可以將內(nèi)部嵌套事務(wù)放在try/catch中,并且不繼續(xù)往上拋異常。這樣就能保證,如果內(nèi)部嵌套事務(wù)中出現(xiàn)異常,只回滾內(nèi)部事務(wù),而不影響外部事務(wù)。

十三、編程式事務(wù)

上面的事務(wù)失效都是基于@Transactional注解的,我們把這種事務(wù)叫做:聲明式事務(wù)。

其實,spring還提供了另外一種創(chuàng)建事務(wù)的方式,即通過手動編寫代碼實現(xiàn)的事務(wù),我們把這種事務(wù)叫做:編程式事務(wù)。

@Service
public class DemoService {
    

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Transactional(rollbackFor = Exception.class)
    public  void query(Demo demo) throws Exception{
       transactionTemplate.execute((status -> {
           save(demo);
           return Boolean.TRUE;
       }));
    }

    @Transactional
    public void save(Demo demo) {

    }
}

在spring中為了支持編程式事務(wù),專門提供了一個類:TransactionTemplate,在它的execute方法中,就實現(xiàn)了事務(wù)的功能。

使用TransactionTemplate的編程式事務(wù)可以

  • 避免由于spring aop問題,導(dǎo)致事務(wù)失效的問題。
  • 能夠更小粒度的控制事務(wù)的范圍。

tips:關(guān)于本文舉例的query加事務(wù)不太符合開發(fā)的要求,但是有點懶就不改了

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

相關(guān)文章

  • Spring根據(jù)URL參數(shù)進行路由的方法詳解

    Spring根據(jù)URL參數(shù)進行路由的方法詳解

    這篇文章主要給大家介紹了關(guān)于Spring根據(jù)URL參數(shù)進行路由的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起來看看吧。
    2017-12-12
  • MyBatis攔截器動態(tài)替換表名的方法詳解

    MyBatis攔截器動態(tài)替換表名的方法詳解

    因為我們持久層框架更多地使用MyBatis,那我們就借助于MyBatis的攔截器來完成我們的功能,這篇文章主要給大家介紹了關(guān)于MyBatis攔截器動態(tài)替換表名的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • Java隊列數(shù)據(jù)結(jié)構(gòu)的實現(xiàn)

    Java隊列數(shù)據(jù)結(jié)構(gòu)的實現(xiàn)

    這篇文章主要介紹了Java隊列數(shù)據(jù)結(jié)構(gòu)的實現(xiàn),隊列是一種特殊的線性表,只允許在表的隊頭進行刪除操作,在表的后端進行插入操作,隊列是一個有序表先進先出,想了解更多相關(guān)資料的小伙伴可以參考下面文章的詳細(xì)內(nèi)容
    2021-12-12
  • 深入了解JAVA數(shù)據(jù)類型與運算符

    深入了解JAVA數(shù)據(jù)類型與運算符

    這篇文章主要介紹了Java基本數(shù)據(jù)類型和運算符,結(jié)合實例形式詳細(xì)分析了java基本數(shù)據(jù)類型、數(shù)據(jù)類型轉(zhuǎn)換、算術(shù)運算符、邏輯運算符等相關(guān)原理與操作技巧,需要的朋友可以參考下
    2021-07-07
  • Springboot打印接口的三種方式分享

    Springboot打印接口的三種方式分享

    這篇文章主要為大家詳細(xì)介紹了Springboot打印接口的三種方式:aop切面的方式、過濾器的方式和攔截器的方式,感興趣的可以跟隨小編一起學(xué)習(xí)一下
    2022-08-08
  • 一篇文章帶你了解java接口與繼承

    一篇文章帶你了解java接口與繼承

    這篇文章主要介紹了Java接口和繼承操作,結(jié)合具體實例形式分析了Java接口和繼承與使用的相關(guān)原理、操作技巧與注意事項,需要的朋友可以參考下
    2021-08-08
  • java編程題之順時針打印矩陣

    java編程題之順時針打印矩陣

    這篇文章主要為大家詳細(xì)介紹了java編程題之順時針打印矩陣,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • java結(jié)合keytool如何實現(xiàn)非對稱簽名和驗證詳解

    java結(jié)合keytool如何實現(xiàn)非對稱簽名和驗證詳解

    這篇文章主要給大家介紹了關(guān)于java結(jié)合keytool如何實現(xiàn)非對稱簽名和驗證的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • Java Servlet線程中AsyncContext異步處理Http請求

    Java Servlet線程中AsyncContext異步處理Http請求

    這篇文章主要介紹了Java Servlet線程中AsyncContext異步處理Http請求及在業(yè)務(wù)中應(yīng)用,AsyncContext是Servlet 3.0使Servlet 線程不再需要一直阻塞,直到業(yè)務(wù)處理完畢才能再輸出響應(yīng),最后才結(jié)束該Servlet線程
    2023-03-03
  • 用Java實現(xiàn)小球碰壁反彈的簡單實例(算法十分簡單)

    用Java實現(xiàn)小球碰壁反彈的簡單實例(算法十分簡單)

    下面小編就為大家?guī)硪黄肑ava實現(xiàn)小球碰壁反彈的簡單實例(算法十分簡單)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08

最新評論