最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

并行Stream與Spring事務相遇會發(fā)生什么?

 更新時間:2022年05月25日 14:17:12   作者:??程序新視界????  
這篇文章主要介紹了并行Stream與Spring事務相遇會發(fā)生什么?文章主要解決實戰(zhàn)中的Bug及解決方案和技術延伸,具有一定的參考價值,需要的小伙伴可以參考一下

前言:

事情是這樣的:運營人員反饋,通過Excel導入數(shù)據(jù)時,有一部分成功了,有一部分未導入。初步猜測,是事務未生效導致的。查看代碼,發(fā)現(xiàn)導入部分已經(jīng)通過@Transcational注解進行事務控制了,為什么還會出現(xiàn)事務不生效的問題呢?下面我們就進行具體的案例分析,Let's go!

事務不生效的代碼

這里寫一段簡單的偽代碼來演示展示一下事務不生效的代碼:

  @Transactional(rollbackFor = Exception.class)
  public void batchInsert(List<Order> list) {
    list.parallelStream().forEach(order -> orderMapper.save(order));
  }

邏輯很簡單,遍歷list,然后批量插入Order數(shù)據(jù)到數(shù)據(jù)庫。在該方法上使用@Transactional來聲明出現(xiàn)異常時進行回滾。

但事實情況是,其中某一條數(shù)據(jù)執(zhí)行異常時,事務并沒有進行回滾。這到底是為什么呢?

下面一探究竟。

JDK 8 的Stream

上面代碼中涉及到了兩個知識點:parallelStream和@Transactional,我們先來鋪墊一下parallelStream相關知識。

在JDK8 中引入了Stream API的概念和實現(xiàn),這里的Stream有別于 InputStream 和OutputStream,Stream API 是處理對象流而不是字節(jié)流。

比如,我們可以通過如下方式來基于Stream進行實現(xiàn):

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); 
numbers.stream().forEach(num->System.out.println(num));

輸出:1 2 3 4 5 6 7 8 9

代碼看起來方便清爽多了。

關于Stream的基本處理流程如下:

在這些Stream API中,還提供了一個并行處理的API,也就是parallelStream。它可以將任務拆分子任務,分發(fā)給多個處理器同時處理,之后合并。這樣做的目的很明顯是為了提升處理效率。

parallelStream的基本使用方式如下:

// 并行執(zhí)行流
list.stream().parallel().filter(e -> e > 10).count()

針對上述代碼,對應的流程如下:

而parallelStream會將流劃分成多個子流,分散到不同的CPU并行處理,然后合并處理結(jié)果。其中,parallelStream默認是基于ForkJoinPool.commonPool()線程池來實現(xiàn)并行處理的。

通常情況下,我們可以認為并行會比串行快,但還是有前提條件的:

  • 處理器核心數(shù)量:并行處理核心數(shù)越多,處理效率越高;
  • 處理數(shù)據(jù)量:處理數(shù)據(jù)量越大優(yōu)勢越明顯;

但并行處理也面臨著一系列的問題,比如:資源競爭、死鎖、線程切換、事務、可見性、線程安全等問題。

@Transactional事務處理

上面了解了parallelStream的基本原理及特性之后,再來看看@Transactional的事務處理特性。

@Transactional是Spring提供的基于注解的一種聲明式事務方式,該注解只能運用到public的方法上。

基本原理:當一個方法被@Transactional注解之后,Spring會基于AOP在方法執(zhí)行之前開啟一個事務。當方法執(zhí)行完畢之后,根據(jù)方法是否報錯,來決定回滾或提交事務。

在默認代理模式下,只有目標方法由外部方法調(diào)用時,才能被Spring的事務攔截器攔截。所以,在同一個類中的兩個方法直接調(diào)用,不會被Spring的事務攔截器攔截。這是事務不生效的一個場景,但在上述案例中,并不存在這種情況。

Spring在處理事務時,會從連接池中獲得一個jdbc connection,將連接綁定到線程上(基于ThreadLocal),那么同一個線程中用到的就是同一個connection了。具體實現(xiàn)在DataSourceTransactionManager#doBegin方法中。

Bug綜合分析

在了解了parallelStream和@Transactional的相關知識之后,我們會發(fā)現(xiàn):parallelStream處理時開啟了多線程,而@Transactional在處理事務時會(基于ThreadLocal)將連接綁定到當前線程,由于@Transactional綁定管理的是主線程的事務,而parallelStream開啟的新的線程與主線程無關。因此,事務也就無效了。

此時,將parallelStream改為普通的stream,事務可正常回滾。這就提示我們,在使用基于@Transactional方式管理事務時,慎重使用多線程處理。

問題拓展

雖然parallelStream帶來了更高的性能,但也要區(qū)分場景進行使用。即便是在不需要事務管理的情況下,如果parallelStream使用不當,也會造成同一時間對數(shù)據(jù)庫發(fā)起大量請求等問題。

因此,在stream與parallelStream之間進行選擇時,還要考慮幾個問題:

  • 是否需要并行?數(shù)據(jù)量比較大,處理器核心數(shù)比較多的情況下才會有性能提升。
  • 任務之間是否是獨立的,是否會引起任何競態(tài)條件?比如:是否共享變量。
  • 執(zhí)行結(jié)果是否取決于任務的調(diào)用順序?并行執(zhí)行的順序是不確定的。

小結(jié)

文章講述的Bug雖然簡單,但如果不了解parallelStream與@Transactional注解的特性,還是很難排查的。而且也讓我們意識到,雖然Spring通過@Transactional將事務管理進行了簡化處理,但作為開發(fā)者,還是需要深入了解一下它的基本運作原理。不然,在排查bug時,很容易踩坑。

到此這篇關于并行Stream與Spring事務相遇會發(fā)生什么?的文章就介紹到這了,更多相關 Stream與Spring 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 使用Spring MVC攔截器實現(xiàn)日志記錄的方法

    使用Spring MVC攔截器實現(xiàn)日志記錄的方法

    本篇文章主要介紹了使用Spring MVC攔截器實現(xiàn)日志記錄的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • Javafx利用fxml變換場景的實現(xiàn)示例

    Javafx利用fxml變換場景的實現(xiàn)示例

    本文主要介紹了Javafx利用fxml變換場景的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-07-07
  • Java內(nèi)存溢出的幾個區(qū)域總結(jié)(注意避坑!)

    Java內(nèi)存溢出的幾個區(qū)域總結(jié)(注意避坑!)

    內(nèi)存溢出是指應用系統(tǒng)中存在無法回收的內(nèi)存或使用的內(nèi)存過多,最終使得程序運行要用到的內(nèi)存大于虛擬機能提供的最大內(nèi)存,下面這篇文章主要給大家介紹了關于Java內(nèi)存溢出的幾個區(qū)域,總結(jié)出來給大家提醒注意避坑,需要的朋友可以參考下
    2022-11-11
  • Mybatis-plus3.4.3下使用lambdaQuery報錯解決

    Mybatis-plus3.4.3下使用lambdaQuery報錯解決

    最近在使用lambdaQuery().eq(CommonUser::getOpenId, openId).one()進行查詢報錯,本文主要介紹了Mybatis-plus3.4.3下使用lambdaQuery報錯解決,具有一定的參考價值,感興趣的可以了解一下
    2024-07-07
  • java原生序列化和Kryo序列化性能實例對比分析

    java原生序列化和Kryo序列化性能實例對比分析

    這篇文章主要介紹了java原生序列化和Kryo序列化性能實例對比分析,涉及Java和kryo序列化和反序列化相關實例,小編覺得很不錯,這里分享給大家,希望給大家一個參考。
    2017-10-10
  • Springboot在IDEA熱部署的配置方法

    Springboot在IDEA熱部署的配置方法

    這篇文章主要介紹了Springboot在IDEA熱部署的配置方法,給大家補充介紹了Intellij IDEA 4種配置熱部署的方法,需要的朋友可以參考下
    2018-04-04
  • 詳解Java分布式IP限流和防止惡意IP攻擊方案

    詳解Java分布式IP限流和防止惡意IP攻擊方案

    這篇文章主要介紹了詳解Java分布式IP限流和防止惡意IP攻擊方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • 詳解Java中final的用法

    詳解Java中final的用法

    本文主要介紹了Java中final的使用方法,final是java的關鍵字,本文就詳細說明一下它的使用方法,需要的朋友可以參考下
    2015-08-08
  • 詳解Kotlin中如何實現(xiàn)類似Java或C#中的靜態(tài)方法

    詳解Kotlin中如何實現(xiàn)類似Java或C#中的靜態(tài)方法

    Kotlin中如何實現(xiàn)類似Java或C#中的靜態(tài)方法,本文總結(jié)了幾種方法,分別是:包級函數(shù)、伴生對象、擴展函數(shù)和對象聲明。這需要大家根據(jù)不同的情況進行選擇。
    2017-05-05
  • springboot aspect通過@annotation進行攔截的實例代碼詳解

    springboot aspect通過@annotation進行攔截的實例代碼詳解

    這篇文章主要介紹了springboot aspect通過@annotation進行攔截的方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08

最新評論

彰化市| 吉首市| 嵊州市| 吴桥县| 孝感市| 邓州市| 隆子县| 迭部县| 罗甸县| 南皮县| 张家口市| 高淳县| 额尔古纳市| 太原市| 浪卡子县| 利津县| 长泰县| 长治市| 阳曲县| 西充县| 海口市| 迁安市| 都江堰市| 寿宁县| 苗栗县| 德昌县| 天祝| 云霄县| 凤山市| 临安市| 淮滨县| 昆明市| 武山县| 田东县| 永靖县| 永清县| 婺源县| 黔西县| 察哈| 新河县| 淳安县|