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

Spring事務(wù)原理解析

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

前言

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

問題描述

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

代碼復(fù)現(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";
}
  • 最少的代碼進(jìn)行演示,Controller方法體中的內(nèi)容應(yīng)是Service中的代碼
  • DistributedLock中封裝的Redission
  • 通過將先讀后改的方式演示,實(shí)際中本質(zhì)就是進(jìn)行了這樣的操作,但會(huì)存在更多的業(yè)務(wù)代碼(不演示新增的情況)

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

排查

1. 鎖失效

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

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

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

select @@tx_isolation;

結(jié)果

REPEATABLE-READ

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

3. 修改Spring事務(wù)傳播配置

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

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

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

解決方案

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

原因?yàn)椋翰l(fā)情境下,執(zhí)行速度過快,很有可能發(fā)生:請求線程在釋放鎖后沒有來得及提交事務(wù),另一個(gè)請求線程在加鎖處被喚醒,繼而讀取到了事務(wù)未提交的數(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");
    }
}
  • 將需要加鎖的事務(wù)代碼進(jìn)行提取另一個(gè)方法
  • 調(diào)用方法中進(jìn)行加鎖,并且必須要去掉事務(wù)注解
  • 因?yàn)槭窃诜鞘聞?wù)方法調(diào)用事務(wù)方法,為了保證事務(wù)生效,需要通過事務(wù)代理Bean進(jìn)行調(diào)用

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

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

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

相關(guān)文章

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

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

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

    IDEA中maven依賴報(bào)紅的問題解決辦法

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

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

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

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

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

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

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

    Spring?WebFlux怎么進(jìn)行異常處理源碼解析

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

    ThreadPoolExecutor線程池的使用方法

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

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

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

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

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

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

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

最新評論

昆明市| 景谷| 临夏县| 洞头县| 玉田县| 民权县| 通州市| 米易县| 花垣县| 泸西县| 内黄县| 礼泉县| 永丰县| 大英县| 临漳县| 和硕县| 崇文区| 孟连| 高清| 红河县| 郴州市| 都江堰市| 兰西县| 广丰县| 九江县| 杭州市| 丹寨县| 睢宁县| 密山市| 息烽县| 巴彦淖尔市| 木里| 绵竹市| 大余县| 平南县| 丹寨县| 伊金霍洛旗| 中卫市| 兴国县| 米泉市| 永康市|