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

Spring事務(wù)原理解析

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

前言

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

問題描述

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

代碼復(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
  • 通過將先讀后改的方式演示,實際中本質(zhì)就是進(jìn)行了這樣的操作,但會存在更多的業(yè)務(wù)代碼(不演示新增的情況)

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

排查

1. 鎖失效

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

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

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

select @@tx_isolation;

結(jié)果

REPEATABLE-READ

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

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

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

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

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

解決方案

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

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

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

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

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

相關(guān)文章

  • Java增強(qiáng)for循環(huán)的增刪操作代碼

    Java增強(qiáng)for循環(huán)的增刪操作代碼

    Foreach循環(huán)(Foreach loop)是計算機(jī)編程語言中的一種控制流程語句,通常用來循環(huán)遍歷數(shù)組或集合中的元素,本文通過實例演示普通for循環(huán)和foreach循環(huán)使用,java增強(qiáng)for循環(huán)的操作代碼感興趣的朋友一起看看吧
    2024-02-02
  • java實現(xiàn)Excel的導(dǎo)入、導(dǎo)出

    java實現(xiàn)Excel的導(dǎo)入、導(dǎo)出

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)Excel的導(dǎo)入、導(dǎo)出的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • springmvc fastjson 反序列化時間格式化方法(推薦)

    springmvc fastjson 反序列化時間格式化方法(推薦)

    下面小編就為大家?guī)硪黄猻pringmvc fastjson 反序列化時間格式化方法(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • 淺析IDEA如何正確配置Gradle? GRADLE_USER_HOME 和 Gradle user home的區(qū)別

    淺析IDEA如何正確配置Gradle? GRADLE_USER_HOME 和 Gradle user home的區(qū)別

    這篇文章主要介紹了IDEA如何正確配置Gradle? GRADLE_USER_HOME 和 Gradle user home的區(qū)別,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • mybatis攔截器無法注入spring bean的問題解決

    mybatis攔截器無法注入spring bean的問題解決

    本文主要介紹了mybatis攔截器無法注入spring bean的問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-02-02
  • 關(guān)于idea剛打開時瘋狂報錯的問題

    關(guān)于idea剛打開時瘋狂報錯的問題

    這篇文章主要介紹了關(guān)于idea剛打開時瘋狂報錯的問題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • 淺談Java生成唯一標(biāo)識碼的三種方式

    淺談Java生成唯一標(biāo)識碼的三種方式

    我們經(jīng)常會遇到這樣的場景,需要生成一個唯一的序列號來表明某一個數(shù)據(jù)的唯一性,本文主要介紹了淺談Java生成唯一標(biāo)識碼的三種方式,感興趣的可以來了解一下
    2022-01-01
  • Java NIO 文件通道 FileChannel 用法及原理

    Java NIO 文件通道 FileChannel 用法及原理

    這篇文章主要介紹了Java NIO 文件通道 FileChannel 用法和原理,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • java枚舉使用詳細(xì)介紹及實現(xiàn)

    java枚舉使用詳細(xì)介紹及實現(xiàn)

    這篇文章主要介紹了java枚舉使用詳細(xì)介紹及實現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Gradle構(gòu)建基本的Web項目結(jié)構(gòu)

    Gradle構(gòu)建基本的Web項目結(jié)構(gòu)

    這篇文章主要為大家介紹了Gradle創(chuàng)建Web項目基本的框架結(jié)構(gòu)搭建,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03

最新評論