国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

@Transactional中使用線程鎖導(dǎo)致了鎖失效,震驚我一整年!

開發(fā) 前端
在@Transactional注解的方法內(nèi)部使用線程鎖時,由于事務(wù)管理和鎖操作在時間上的不一致,可能會導(dǎo)致鎖失效的問題。

今天給大家分享一個線上系統(tǒng)里發(fā)現(xiàn)的生產(chǎn)實踐案例,就是平時大家應(yīng)該都會用@Transactional注解去實現(xiàn)事務(wù)是不是?因為這個注解底層說白了很簡單,就是會去代理你這個方法的執(zhí)行,一旦代理了你的方法執(zhí)行,其實就可以在方法執(zhí)行前開一個事務(wù),方法執(zhí)行完以后如果成功就提交事務(wù),有異常就回滾事務(wù)。

這樣就可以讓你這個方法里所有的數(shù)據(jù)庫操作匯集到一個事務(wù)里去了,這個相信大家其實都是懂的,平時 開發(fā)也都是這么做的。

那大家有沒有想過,要是我們在這個事務(wù)注解里用了多線程并發(fā)加鎖的代碼,可能會導(dǎo)致這個鎖失效,也就是沒法實現(xiàn)多線程在加鎖代碼里串行加鎖執(zhí)行?這個簡直是一個巨坑,妥妥的線上生產(chǎn)事故案例,下面我們就開始分下這個案例。

一、@Transactional與線程鎖的基本使用

首先,我們簡要回顧一下@Transactional和線程鎖的基本用法。

1. @Transactional注解

@Transactional注解可以應(yīng)用于接口定義、接口中的方法、類定義或類中的public方法上。其主要作用是聲明一個方法需要在事務(wù)環(huán)境中執(zhí)行。Spring框架會在運行時通過AOP(面向切面編程)代理機制,自動管理事務(wù)的開啟、提交和回滾。

@Service
public class SomeService {


    @Transactional
    public void someTransactionalMethod() {
        // 業(yè)務(wù)邏輯
    }
}

2. 線程鎖(如ReentrantLock)

線程鎖用于控制多個線程對共享資源的并發(fā)訪問,防止數(shù)據(jù)不一致的問題。ReentrantLock是Java并發(fā)包java.util.concurrent.locks中的一個類,它提供了比synchronized關(guān)鍵字更靈活的鎖定操作。

public class SomeClass {
    private final Lock lock = new ReentrantLock();


    public void someMethod() {
        lock.lock();
        try {
            // 業(yè)務(wù)邏輯
        } finally {
            lock.unlock();
        }
    }
}

二、@Transactional中使用線程鎖導(dǎo)致的問題

在@Transactional注解的方法內(nèi)部使用線程鎖時,可能會遇到鎖失效的問題。這是因為@Transactional通過AOP在目標方法執(zhí)行前后進行事務(wù)的開啟和提交,而線程鎖則直接作用于方法內(nèi)部的代碼塊。這種機制上的差異導(dǎo)致了事務(wù)和鎖的管理在時間上不一致,進而引發(fā)鎖失效。

示例場景

假設(shè)我們有一個服務(wù)類,其中有一個方法需要在事務(wù)環(huán)境中更新數(shù)據(jù)庫記錄,并在這個過程中使用線程鎖控制并發(fā)訪問。

@Service
public class UpdateService {


    private final Lock lock = new ReentrantLock();


    @Transactional
    public void updateData() {
        lock.lock();
        try {
            // 模擬數(shù)據(jù)庫更新操作
            System.out.println("Updating data...");
            // 假設(shè)這里有一些耗時的數(shù)據(jù)庫操作
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }
}

在這個例子中,雖然我們在方法內(nèi)部使用了ReentrantLock來加鎖,但鎖的釋放是在事務(wù)提交之前完成的。如果在鎖釋放后、事務(wù)提交前,有其他線程進入并嘗試更新相同的數(shù)據(jù),就可能讀取到未提交的數(shù)據(jù),從而導(dǎo)致數(shù)據(jù)不一致。

因為一旦把事務(wù)和鎖放一起用,就會顯得有點詭異,你上面的代碼想的是說用事務(wù)注解控制數(shù)據(jù)庫事務(wù),異常就回滾,成功就提交,對吧?然后你想加鎖以后就是每個線程串行執(zhí)行,一個線程加鎖,更新數(shù)據(jù)庫,提交事務(wù),釋放鎖,下一個線程過來加鎖,讀取更新數(shù)據(jù)庫,注意,這里應(yīng)該是接著上一個現(xiàn)成的更新結(jié)果來做的,完了再提交事務(wù),釋放鎖,對吧?

問題是,如果忽略了事務(wù)注解的工作機制,忘了那個事務(wù)控制其實是在鎖代碼外面的,因為spring會用AOP代理機制接管方法執(zhí)行,事務(wù)管控是在方法執(zhí)行外面的,所以很可能你開啟一共事務(wù),然后加鎖,執(zhí)行數(shù)據(jù)庫更新,接著就直接釋放鎖了,然后此時事務(wù)可能還沒提交!!!!

接著別的線程就可以進入一個方法了,此時他會開啟一個自己的事務(wù),在mysql層面多個事務(wù)并發(fā)的時候是有自己的隔離機制的,跟你的代碼里的加鎖是沒直接關(guān)系的,此時新的線程是可以進入代碼塊拿到鎖的,畢竟你之前一個線程都釋放代碼里的鎖了!

然后新的線程執(zhí)行數(shù)據(jù)庫的讀取和更新操作,其實是基于上一個線程的事務(wù)沒提交的那個臟數(shù)據(jù)在執(zhí)行,所以此時就會出現(xiàn)數(shù)據(jù)不一致的情況,看起來就跟多個線程亂序更新數(shù)據(jù)庫一樣,跟你想的就不一樣了,對吧?

所以這就是所謂的事務(wù)注解里線程加鎖可能導(dǎo)致鎖沒生效,多個線程還是亂序在執(zhí)行。

三、問題分析

問題的根源在于@Transactional和線程鎖的管理機制不同步。@Transactional通過AOP代理在方法執(zhí)行前后進行事務(wù)操作,而線程鎖則是直接在方法內(nèi)部控制并發(fā)。當(dāng)方法執(zhí)行完畢后,即使事務(wù)還未提交,鎖已經(jīng)被釋放,這就為其他線程提供了進入并操作共享資源的機會。

四、解決方案

為了解決@Transactional中使用線程鎖導(dǎo)致的鎖失效問題,我們可以采用以下幾種方案:

1. 將事務(wù)管理和鎖操作分離

將需要加鎖的業(yè)務(wù)邏輯封裝到一個單獨的方法中,并在調(diào)用該方法前手動管理事務(wù)。這種方式可以避免@Transactional和線程鎖在時間上的不一致。也就是通過手動管控事務(wù)提交和回滾,跟代碼里的加鎖同步一致,避免這個問題。

按照我們的想法,說白了就是應(yīng)該是在加鎖代碼里面讓事務(wù)先提交,然后再釋放鎖,這樣就可以保證多個線程對數(shù)據(jù)庫的更新是串行的。

@Service
public class UpdateService {


    private final Lock lock = new ReentrantLock();


    @Autowired
    private PlatformTransactionManager transactionManager;


    public void updateData() {
        lock.lock();
        try {
            TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
            try {
                // 模擬數(shù)據(jù)庫更新操作
                System.out.println("Updating data...");
                // 假設(shè)這里有一些耗時的數(shù)據(jù)庫操作
                Thread.sleep(1000);
                transactionManager.commit(status);
            } catch (Exception e) {
                transactionManager.rollback(status);
                throw e;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }
}

注意:這種方式雖然解決了鎖失效的問題,但手動管理事務(wù)會使代碼變得復(fù)雜,且容易出錯。

2. 使用@Transactional單獨一個方法

將需要事務(wù)支持的方法單獨提出來,并確保該方法不包含任何鎖操作。在調(diào)用該方法前,通過其他方式(如使用代理類或直接在調(diào)用者處)管理鎖。這個本質(zhì)其實也是在鎖范圍內(nèi)讓事務(wù)先執(zhí)行和提交,只不過通過方法的提取避免了手動加提交事務(wù),其實是更加的優(yōu)雅的!

@Service
public class UpdateServiceImpl implements UpdateService {


    @Autowired
    @Lazy
    private UpdateServiceImpl self;


    private final Lock lock = new ReentrantLock();


    @Transactional
    public void updateDataTransactional() {
        // 模擬數(shù)據(jù)庫更新操作
        System.out.println("Updating data in transaction...");
        // 假設(shè)這里有一些耗時的數(shù)據(jù)庫操作
        Thread.sleep(1000);
    }


    public void updateData() {
        lock.lock();
        try {
            self.updateDataTransactional();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }
}

這種方式將事務(wù)管理和鎖操作分離到不同的方法中,既保證了事務(wù)的正確性,又避免了鎖失效的問題。

3. 使用數(shù)據(jù)庫鎖代替線程鎖

在某些情況下,我們可以考慮使用數(shù)據(jù)庫本身的鎖機制來替代線程鎖。數(shù)據(jù)庫鎖可以更加精確地控制對共享資源的訪問,且與事務(wù)管理緊密結(jié)合,不易出現(xiàn)鎖失效的問題。

五、總結(jié)

在@Transactional注解的方法內(nèi)部使用線程鎖時,由于事務(wù)管理和鎖操作在時間上的不一致,可能會導(dǎo)致鎖失效的問題。為了解決這個問題,我們可以將事務(wù)管理和鎖操作分離,使用編程式事務(wù)管理,或者將需要事務(wù)支持的方法單獨提出來,并通過其他方式管理鎖。同時,我們也可以考慮使用數(shù)據(jù)庫鎖來替代線程鎖,以更好地保證數(shù)據(jù)的一致性和完整性。

希望這篇文章能幫助你更好地理解@Transactional中使用線程鎖導(dǎo)致的問題,并提供實用的解決方案。在實際開發(fā)中,根據(jù)具體場景選擇合適的方法,可以有效避免類似問題的發(fā)生。

責(zé)任編輯:武曉燕 來源: 石杉的架構(gòu)筆記
相關(guān)推薦

2025-04-11 01:00:00

線程鎖Spring事務(wù)

2018-06-05 08:45:50

系統(tǒng)蘋果軟件

2017-08-11 15:56:03

內(nèi)存價格暴漲

2013-11-29 10:02:41

移動廣告鎖屏分發(fā)

2020-12-18 08:28:13

Redis數(shù)據(jù)數(shù)據(jù)庫

2020-08-26 08:59:58

Linux線程互斥鎖

2022-09-14 19:50:22

事務(wù)場景流程

2020-03-27 16:27:03

Redis數(shù)據(jù)庫

2023-09-08 08:52:12

Spring注解事務(wù)

2023-08-29 10:51:44

2021-01-15 09:40:37

程序員技能開發(fā)者

2020-02-21 20:21:45

線程共享資源

2017-05-08 11:46:15

Java多線程

2019-04-12 15:14:44

Python線程

2017-05-31 14:03:07

Java多線程內(nèi)置鎖與顯示鎖

2023-09-28 09:07:54

注解失效場景

2019-01-04 11:18:35

獨享鎖共享鎖非公平鎖

2019-11-28 16:00:06

重入鎖讀寫鎖樂觀鎖

2022-07-12 08:56:18

公平鎖非公平鎖Java

2022-06-15 07:32:35

Lock線程Java
點贊
收藏

51CTO技術(shù)棧公眾號

欧美色图天堂网| 白浆爆出在线观看| 国产精品普通话对白| 欧美日韩综合网| 久久久精品日韩| 欧洲xxxxx| 国产精品网站在线播放| 免费男女羞羞的视频网站主页在线观看| 黑人巨大精品欧美一区二区免费| 蜜桃视频网站在线| 久久综合999| 黄瓜视频免费观看在线观看www| 欧美伊人影院| 精品国产91九色蝌蚪| 国产在线精彩视频| 色多多国产成人永久免费网站| 精品一区二区三区亚洲| 国产在线观看一区二区三区| 国产在线日韩| 男人添女荫道口图片| 亚洲人成网站色在线观看| 中文字幕免费在线视频| 7777女厕盗摄久久久| 国外成人福利视频| 国产va免费精品高清在线| 国产模特精品视频久久久久| 欧美视频第一区| 欧美视频你懂的| 视频精品一区| 久久99九九| 国产精品久久免费看| 污视频网站免费在线观看| 欧美精品video| 亚洲视频播放| 国产精品视频分类| 91精品国产乱| 久久免费视频66| 久久精品日产第一区二区三区| 久久久不卡网国产精品一区| 91精品国产91久久久久游泳池 | 伊人在我在线看导航| 蜜臀久久99精品久久久久久宅男| 日韩精品水蜜桃| 国产爆乳无码一区二区麻豆| 亚洲一区二区三区四区五区黄| 操人在线观看| 91免费版黄色| 久久久久久久综合日本| 黄色在线视频网站| 日韩av日韩在线观看| 国产成人午夜精品影院观看视频| 黄色av网站在线| 2018国产精品视频| 久久97超碰色| av在线二区| 日韩美女福利视频| 91美女福利视频| 欧美日韩国产观看视频| 成人羞羞视频免费| 亚洲精品国产视频| 深夜福利亚洲| 免费成人进口网站| 91精品在线麻豆| 欧美一区精品| 日本女优北野望在线电影| 视频直播国产精品| 裸体在线国模精品偷拍| aaa在线观看| 91九色国产社区在线观看| 国产精品乱码人人做人人爱| 日本美女久久| 麻豆映画在线观看| 亚洲国产欧美一区二区三区久久| 一区三区视频| 免费在线视频一级不卡| 日本老师69xxx| 国产精品人妖ts系列视频 | 色综合91久久精品中文字幕| 激情六月婷婷久久| 青青在线视频| 欧美动漫一区二区| 欧美三级视频在线观看| 日韩精品网站| 97福利网站在线观看视频| 欧美精品videos另类日本| 丁香桃色午夜亚洲一区二区三区| 91破解版在线观看| 亚洲日韩中文字幕| 激情综合五月婷婷| 欧亚av在线| 黄色特一级视频| 亚洲一区二区久久| 国产精品一卡二卡在线观看| 九色porny自拍视频在线观看| 先锋影音一区二区三区| 欧美一二三四区在线| 欧美一区=区| 国产成人无吗| 国产精品初高中精品久久| 欧美日韩亚洲高清| 中国精品18videos性欧美| 欧美白人做受xxxx视频| 不卡视频一区二区三区| 欧美三级韩国三级日本三斤| 99国产精品私拍| 曰本三级在线| 欧美xxxx吸乳| 中文字幕亚洲一区二区三区| 99久久精品国产毛片| 亚洲一区二区免费在线观看| 午夜久久久精品| 国产精品美女久久久久久免费| 精品日本高清在线播放| 一区久久精品| 看黄在线观看| 播放灌醉水嫩大学生国内精品| 久久免费视频在线观看| 亚洲一区二区三区不卡国产欧美 | 超碰国产精品久久国产精品99| 在线视频综合导航| 天堂资源在线中文精品| 欧美极品免费| 日韩av卡一卡二| 国产欧美精品日韩精品| 日韩欧美一区视频| 久久久久久自在自线| 欧美男女交配| 91网址在线播放| 国产精品偷伦免费视频观看的| 欧美三级电影网| 粉嫩13p一区二区三区| 国产精品网站在线看| 麻豆av电影在线观看| 亚洲mv在线看| 欧美国产日本在线| 婷婷国产在线综合| 蜜桃av噜噜一区二区三区小说| www.26天天久久天堂| 成人短剧在线观看| 久久伊人资源站| 久久综合色88| 日韩欧美亚洲成人| 国产不卡视频在线播放| 国产精品午夜一区二区三区| 中文在线字幕免费观看| 色婷婷综合久久久久中文字幕 | 亚洲综合社区| 国产一区二区视频在线看 | 精品久久久久久最新网址| 国产成人一区在线| 久久中文字幕av一区二区不卡| 久久99亚洲网美利坚合众国| 亚洲一级片免费| 黄色国产精品一区二区三区| 中文字幕av一区中文字幕天堂| 午夜私人影院久久久久| 国产精品一区二区在线观看网站| 精品国产不卡| 裤袜国产欧美精品一区| 调教在线观看| 婷婷无套内射影院| 好看的日韩精品视频在线| 久久成人精品电影| 欧美一区午夜视频在线观看| 欧美激情在线看| 奇米综合一区二区三区精品视频| 免费短视频成人日韩| 欧美magnet| 蜜桃视频在线观看视频| 久久久久久久久久网| 黄色一区三区| 日本精品久久中文字幕佐佐木| 日韩精品黄色网| 91黄色免费观看| 亚洲国产精品二十页| 久久99久久久欧美国产| 国产精品欧美在线观看| 91成人在线| 2021国产在线| 三级av在线播放| 欧美wwwwwww| 永久免费看av| 精品国产区在线| 国产精品青青在线观看爽香蕉 | 奇米精品一区二区三区在线观看 | 香蕉视频在线免费看| 99热免费在线| 国产av熟女一区二区三区| 97超碰最新| 国产91久久婷婷一区二区| 亚洲午夜久久久影院| 欧美精品久久久久久久多人混战| 一区二区视频在线看| 久久精品在线免费观看| 国产一区高清在线| 久久综合九色| 欧美午夜不卡| 国产精品久久久乱弄| 你懂的视频欧美| 香蕉免费一区二区三区在线观看|