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

Spring事務原理解析

 更新時間:2022年12月20日 09:22:10   作者:碼畜c  
Spring事務有可能會提交,回滾、掛起、恢復,所以Spring事務提供了一種機制,可以讓程序員來監(jiān)聽當前Spring事務所處于的狀態(tài),這篇文章主要介紹了Spring底層事務原理,需要的朋友可以參考下

前言

最近在編寫公司APP產(chǎn)品的商品砍價功能,其中有一個接口涉及并發(fā)訪問。自測時通過ApiFox接口管理工具進行壓測,落地數(shù)據(jù)時出現(xiàn)了"鎖失效"的情景。十分感謝后端小伙伴的幫助排查,解決了這個問題。

問題描述

并發(fā)接口中,先對主表數(shù)據(jù)進行讀取,進行業(yè)務判斷后,新增、修改它表的數(shù)據(jù)。在理應串行執(zhí)行的情況下發(fā)生了多個請求線程讀取到了相同的主表數(shù)據(jù),導致數(shù)據(jù)處理異常。也正是前言中所說的"鎖失效"了。(實際情況加鎖操作是有效的)

代碼復現(xiàn)

@RequestMapping("/test")
@Transactional(rollbackFor = Exception.class)
public String test() {
    DistributedLock.lock("ct_lock");
    try {
        Map<String, Object> resultMap = jdbcTemplate.queryForMap("select * from concurrent_read_uncommit");
        int num = Integer.parseInt(resultMap.get("num").toString());
        num++;
        jdbcTemplate.update("update concurrent_read_uncommit set num = " + num);
    } finally {
        DistributedLock.unlock("ct_lock");
    }
    return "success";
}
  • 最少的代碼進行演示,Controller方法體中的內(nèi)容應是Service中的代碼
  • DistributedLock中封裝的Redission
  • 通過將先讀后改的方式演示,實際中本質就是進行了這樣的操作,但會存在更多的業(yè)務代碼(不演示新增的情況)

ApiFox中通過創(chuàng)建100個請求線程進行壓測,最終concurrent_read_uncommit表中的num字段值為94,而非100。

排查

1. 鎖失效

新編寫了兩個簡單接口,第一個接口加鎖,并線程休眠30秒后釋放鎖。另一個接口加同樣的鎖,打印一條語句后直接返回。先調(diào)用第一個接口,在調(diào)用第二個接口。Debug中發(fā)現(xiàn)鎖是有效的,在redis中存有鎖Key。并且訪問第二個接口時,線程被阻塞在了加鎖行代碼。

2. 事務隔離級別

查詢數(shù)據(jù)庫事務默認隔離級別:

select @@tx_isolation;

結果

REPEATABLE-READ

就是默認的RR級別,那么說明同個事務內(nèi)多次讀取數(shù)據(jù)都會是一樣的,不會讀取到臟數(shù)據(jù)。

3. 修改Spring事務傳播配置

@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)

與這個并沒有關系,八竿子打不著。當時的想法時是多個并發(fā)請求在進入到了同個事務內(nèi),并一起讀取到了沒有被修改前的數(shù)據(jù)。細想想:

  • 事務傳播配置一般用在不同事務方法間產(chǎn)生調(diào)用時的事務決策,是共用事務還是新創(chuàng)建事務,亦或是其他的方式進行處理
  • test方法本身為根方法,也沒有調(diào)用其他的事務方法,所以無需配置事務傳播配置
  • 即便不在同一事務內(nèi),依舊能查詢到其他事務修改但未提交的相同數(shù)據(jù)

解決方案

在鎖代碼塊中調(diào)用事務方法,而不是在事務方法中進行加鎖。

原因為:并發(fā)情境下,執(zhí)行速度過快,很有可能發(fā)生:請求線程在釋放鎖后沒有來得及提交事務,另一個請求線程在加鎖處被喚醒,繼而讀取到了事務未提交的數(shù)據(jù)。即讀取到了臟數(shù)據(jù),產(chǎn)生了"鎖失效"的效果。

修正代碼:

@RequestMapping("/test2")
public String test2() {
    ConcurrentTransactionalController proxyBean = SpringContextUtils.getBean(this.getClass());
    proxyBean.doTest2();
    return "success";
}
@Transactional(rollbackFor = Exception.class)
public void doTest2() {
    DistributedLock.lock("ct_lock");
    try {
        Map<String, Object> resultMap = jdbcTemplate.queryForMap("select * from concurrent_read_uncommit");
        int num = Integer.parseInt(resultMap.get("num").toString());
        num++;
        jdbcTemplate.update("update concurrent_read_uncommit set num = " + num);
        Thread.sleep(500);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    } finally {
        DistributedLock.unlock("ct_lock");
    }
}
  • 將需要加鎖的事務代碼進行提取另一個方法
  • 調(diào)用方法中進行加鎖,并且必須要去掉事務注解
  • 因為是在非事務方法調(diào)用事務方法,為了保證事務生效,需要通過事務代理Bean進行調(diào)用

這樣就保證了不會讀取到事務未提交的數(shù)據(jù),同時又具有鎖的排他性。

其實鎖一直都是有效的,本質原因就在于Spring的事務代理Bean屏蔽了事務代碼。我們不能手動的進行控制,也就是說你變更了不了事務代碼的順序。如果能將提交事務的行代碼寫到釋放鎖之前,就不會存在這個問題了。所以,也可以通過編程式事務解決這個問題,關于編程式事務,Spring也有做代碼封裝。如果不通過編程式事務,那么就只能通過上述代碼變相的來實現(xiàn)。

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

相關文章

  • maven 刪除下載失敗的包的方法

    maven 刪除下載失敗的包的方法

    本文介紹了當Maven包報紅時,使用刪除相關文件的方法來解決該問題,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • IDEA中maven依賴報紅的問題解決辦法

    IDEA中maven依賴報紅的問題解決辦法

    這篇文章主要給大家介紹了關于IDEA中maven依賴報紅的問題解決辦法,在使用IDEA過程中,經(jīng)常會出現(xiàn)maven依賴報紅的問題,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2023-07-07
  • SpringBoot獲取配置文件的簡單實現(xiàn)方法

    SpringBoot獲取配置文件的簡單實現(xiàn)方法

    這篇文章主要給大家介紹了關于SpringBoot如何獲取配置文件的簡單實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Spring Boot具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2020-05-05
  • springboot線程池監(jiān)控的簡單實現(xiàn)

    springboot線程池監(jiān)控的簡單實現(xiàn)

    本文主要介紹了springboot線程池監(jiān)控的簡單實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Java連接超時的幾種情況以及讀取代碼

    Java連接超時的幾種情況以及讀取代碼

    在Java編程中連接超時異常是指在建立網(wǎng)絡連接時,無法在給定的時間內(nèi)成功建立連接的異常,這篇文章主要給大家介紹了關于Java連接超時的幾種情況以及讀取的相關資料,需要的朋友可以參考下
    2024-02-02
  • Spring?WebFlux怎么進行異常處理源碼解析

    Spring?WebFlux怎么進行異常處理源碼解析

    這篇文章主要為大家介紹了Spring?WebFlux怎么進行異常處理源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • ThreadPoolExecutor線程池的使用方法

    ThreadPoolExecutor線程池的使用方法

    這篇文章主要為大家詳細介紹了ThreadPoolExecutor線程池的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • Java微服務Filter過濾器集成Sentinel實現(xiàn)網(wǎng)關限流過程詳解

    Java微服務Filter過濾器集成Sentinel實現(xiàn)網(wǎng)關限流過程詳解

    這篇文章主要介紹了Java微服務Filter過濾器集成Sentinel實現(xiàn)網(wǎng)關限流過程,首先Sentinel規(guī)則的存儲默認是存儲在內(nèi)存的,應用重啟之后規(guī)則會丟失。因此我們通過配置中心Nacos保存規(guī)則,然后通過定時拉取Nacos數(shù)據(jù)來獲取規(guī)則配置,可以做到動態(tài)實時的刷新規(guī)則
    2023-02-02
  • java數(shù)據(jù)類型與二進制詳細介紹

    java數(shù)據(jù)類型與二進制詳細介紹

    這篇文章主要介紹了java數(shù)據(jù)類型與二進制詳細介紹的相關資料,這里對數(shù)據(jù)類型進行了一一介紹分析,并說明自動轉換和強制轉換,需要的朋友可以參考下
    2017-07-07
  • Java中數(shù)據(jù)轉換及字符串的“+”操作方法

    Java中數(shù)據(jù)轉換及字符串的“+”操作方法

    本文主要介紹了Java中的數(shù)據(jù)類型轉換,包括隱式轉換和強制轉換,隱式轉換通常用于將范圍較小的數(shù)據(jù)類型轉換為范圍較大的數(shù)據(jù)類型,而強制轉換則是將范圍較大的數(shù)據(jù)類型轉換為范圍較小的數(shù)據(jù)類型,本文介紹Java中數(shù)據(jù)轉換以及字符串的“+”操作,感興趣的朋友一起看看吧
    2024-10-10

最新評論

靖远县| 太保市| 陆河县| 东宁县| 福海县| 怀仁县| 棋牌| 东乡| 河间市| 霍林郭勒市| 扶余县| 大丰市| 都昌县| 新河县| 丰宁| 马公市| 靖远县| 资中县| 茶陵县| 监利县| 乌兰察布市| 镶黄旗| 筠连县| 盱眙县| 贡觉县| 滕州市| 吕梁市| 高密市| 中方县| 甘孜县| 同心县| 绥化市| 临桂县| 会东县| 贵德县| 亳州市| 内乡县| 靖安县| 柳州市| 大足县| 雅安市|