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

java中樂(lè)觀鎖與悲觀鎖區(qū)別及使用場(chǎng)景分析

 更新時(shí)間:2024年08月04日 09:35:52   作者:kerwin_code  
本文主要介紹了java中樂(lè)觀鎖與悲觀鎖區(qū)別及使用場(chǎng)景分析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、什么是樂(lè)觀鎖?什么是悲觀鎖

個(gè)人理解一句話概括就是,在應(yīng)用層面會(huì)造成線程阻塞的是悲觀鎖,而不會(huì)造成線程阻塞的是樂(lè)觀鎖,為什么這么說(shuō)會(huì)在后續(xù)的內(nèi)容中做詳細(xì)介紹。

1.1、悲觀鎖

  • 悲觀鎖是一種基于悲觀態(tài)度的數(shù)據(jù)并發(fā)控制機(jī)制,用于防止數(shù)據(jù)沖突。它采取預(yù)防性的措施,在修改數(shù)據(jù)之前將其鎖定,并在操作完成后釋放鎖定,以確保數(shù)據(jù)的一致性和完整性。悲觀鎖通常用于并發(fā)環(huán)境下的數(shù)據(jù)庫(kù)系統(tǒng),是數(shù)據(jù)庫(kù)本身實(shí)現(xiàn)鎖機(jī)制的一種方式。

  • 在悲觀鎖的機(jī)制下,當(dāng)一個(gè)使用者要修改某個(gè)數(shù)據(jù)時(shí),首先會(huì)嘗試獲取該數(shù)據(jù)的鎖。如果鎖已經(jīng)被其他使用者持有,則當(dāng)前使用者會(huì)被阻塞,直到對(duì)應(yīng)的鎖被釋放。這種悲觀的態(tài)度認(rèn)為數(shù)據(jù)沖突是不可避免的,因此在修改數(shù)據(jù)之前先鎖定數(shù)據(jù),以防止沖突的發(fā)生。

  • 在Java中,常見(jiàn)的悲觀鎖實(shí)現(xiàn)是使用synchronized關(guān)鍵字或ReentrantLock類(lèi)。這些鎖能夠確保同一時(shí)刻只有一個(gè)線程可以訪問(wèn)被鎖定的代碼塊或資源,其他線程必須等待鎖釋放后才能繼續(xù)執(zhí)行。

1.2、樂(lè)觀鎖

  • 樂(lè)觀鎖是一種基于版本控制的并發(fā)控制機(jī)制。在樂(lè)觀鎖的思想中,認(rèn)為數(shù)據(jù)訪問(wèn)沖突的概率很低,因此不加鎖直接進(jìn)行操作,但在更新數(shù)據(jù)時(shí)會(huì)進(jìn)行版本比對(duì),以確保數(shù)據(jù)的一致性。

  • 樂(lè)觀鎖的原理主要基于版本號(hào)或時(shí)間戳來(lái)實(shí)現(xiàn)。在每次更新數(shù)據(jù)時(shí),先獲取當(dāng)前數(shù)據(jù)的版本號(hào)或時(shí)間戳,然后在更新時(shí)比對(duì)版本號(hào)或時(shí)間戳是否一致,若一致則更新成功,否則表示數(shù)據(jù)已被其他線程修改,更新失敗。

  • 在Java中,常見(jiàn)的樂(lè)觀鎖實(shí)現(xiàn)是使用Atomic類(lèi),例如AtomicIntegerAtomicLong等。這些類(lèi)提供了原子操作,可以確保對(duì)共享資源的更新操作是原子性的,從而避免了鎖的開(kāi)銷(xiāo)和線程等待,另外,CAS(Compare-And-Swap)是實(shí)現(xiàn)樂(lè)觀鎖的核心算法,它通過(guò)比較內(nèi)存中的值是否和預(yù)期的值相等來(lái)判斷是否存在沖突。如果存在,則返回失??;如果不存在,則執(zhí)行更新操作。Java中提供了AtomicInteger、AtomicLongAtomicReference等原子類(lèi)來(lái)支持CAS操作。

二、樂(lè)觀鎖與悲觀鎖分別適用于什么場(chǎng)景

2.1、悲觀鎖適用場(chǎng)景

  • 高并發(fā)且數(shù)據(jù)競(jìng)爭(zhēng)激烈的場(chǎng)景:當(dāng)多個(gè)事務(wù)需要同時(shí)訪問(wèn)和修改同一份數(shù)據(jù)時(shí),使用悲觀鎖可以確保數(shù)據(jù)在任一時(shí)刻只被一個(gè)事務(wù)訪問(wèn)和修改,從而避免數(shù)據(jù)的不一致性和臟讀。
  • 數(shù)據(jù)一致性要求極高的場(chǎng)景:在金融、醫(yī)療等行業(yè)中,對(duì)數(shù)據(jù)的一致性要求非常高,不允許出現(xiàn)任何的數(shù)據(jù)不一致或臟讀現(xiàn)象。在這些場(chǎng)景中,使用悲觀鎖可以確保數(shù)據(jù)在任一時(shí)刻只被一個(gè)事務(wù)訪問(wèn)和修改,從而滿足數(shù)據(jù)一致性的要求。
  • 寫(xiě)操作頻繁的場(chǎng)景:如果系統(tǒng)中寫(xiě)操作(如更新、刪除等)遠(yuǎn)多于讀操作(如查詢),那么使用悲觀鎖可以更有效地保護(hù)數(shù)據(jù),避免在寫(xiě)操作時(shí)被其他事務(wù)干擾。
  • 事務(wù)執(zhí)行時(shí)間較長(zhǎng)的場(chǎng)景:當(dāng)事務(wù)的執(zhí)行時(shí)間較長(zhǎng)時(shí),使用悲觀鎖可以確保在該事務(wù)執(zhí)行期間,數(shù)據(jù)不會(huì)被其他事務(wù)修改,從而避免數(shù)據(jù)的不一致性和臟讀。

2.2、樂(lè)觀鎖適用場(chǎng)景

  • 寫(xiě)操作較少:在這種場(chǎng)景下,多個(gè)事務(wù)或線程大部分時(shí)間都在讀取數(shù)據(jù),而寫(xiě)操作的頻率相對(duì)較低。樂(lè)觀鎖能夠減少鎖的持有時(shí)間,允許多個(gè)事務(wù)或線程同時(shí)讀取數(shù)據(jù),而不會(huì)相互阻塞。
  • 數(shù)據(jù)沖突較少:如果數(shù)據(jù)更新操作之間的沖突較少,即多個(gè)事務(wù)或線程同時(shí)更新同一份數(shù)據(jù)的概率較低,那么樂(lè)觀鎖能夠發(fā)揮很好的性能。因?yàn)榧词古紶柍霈F(xiàn)沖突,也只是在更新數(shù)據(jù)時(shí)才會(huì)被檢測(cè)到,而不需要在整個(gè)數(shù)據(jù)處理過(guò)程中都鎖定資源。
  • 重試成本較低:樂(lè)觀鎖在檢測(cè)到?jīng)_突時(shí)會(huì)回滾事務(wù)或提示沖突,需要客戶端重新嘗試更新操作。因此,如果重試的成本較低(例如,重試不會(huì)導(dǎo)致大量計(jì)算或I/O操作),那么使用樂(lè)觀鎖是合適的。
  • 系統(tǒng)能夠容忍一定程度的失敗:由于樂(lè)觀鎖在更新數(shù)據(jù)時(shí)可能會(huì)因?yàn)榘姹緵_突而失敗,因此系統(tǒng)需要能夠處理這種失敗情況。如果系統(tǒng)能夠容忍一定程度的失?。ɡ纾ㄟ^(guò)重試或其他補(bǔ)償機(jī)制來(lái)恢復(fù)),那么使用樂(lè)觀鎖是可行的。

三、樂(lè)觀鎖與悲觀鎖各自優(yōu)缺點(diǎn)

3.1、悲觀鎖

優(yōu)點(diǎn)

  • 數(shù)據(jù)一致性高:悲觀鎖認(rèn)為沖突一定會(huì)發(fā)生,因此在數(shù)據(jù)處理前會(huì)先加鎖,這樣可以確保數(shù)據(jù)在任一時(shí)刻只被一個(gè)事務(wù)訪問(wèn)和修改,從而避免數(shù)據(jù)的不一致性和臟讀。
  • 簡(jiǎn)單易用:悲觀鎖的實(shí)現(xiàn)相對(duì)簡(jiǎn)單,只需要在操作數(shù)據(jù)前獲取鎖即可。

缺點(diǎn)

  • 性能開(kāi)銷(xiāo)大:悲觀鎖在操作數(shù)據(jù)前需要獲取鎖,如果有大量的并發(fā)操作,可能會(huì)導(dǎo)致性能問(wèn)題,因?yàn)槠渌聞?wù)需要等待鎖釋放。
  • 容易造成死鎖:如果多個(gè)事務(wù)相互等待對(duì)方釋放鎖,可能會(huì)導(dǎo)致死鎖的發(fā)生,影響系統(tǒng)的穩(wěn)定性和可用性。
  • 可能導(dǎo)致資源浪費(fèi):如果獲取鎖后長(zhǎng)時(shí)間不釋放,可能會(huì)導(dǎo)致其他事務(wù)無(wú)法操作數(shù)據(jù),從而造成資源浪費(fèi)。

3.2、樂(lè)觀鎖

優(yōu)點(diǎn)

  • 高并發(fā)高吞吐:樂(lè)觀鎖不會(huì)阻塞其他事務(wù)的讀取操作,只在提交時(shí)檢查數(shù)據(jù)是否被修改,因此可以提供更好的并發(fā)性能。
  • 無(wú)鎖操作:樂(lè)觀鎖不需要顯式地獲取和釋放鎖,減少了鎖競(jìng)爭(zhēng)和上下文切換的開(kāi)銷(xiāo)。
  • 無(wú)死鎖風(fēng)險(xiǎn):由于樂(lè)觀鎖不會(huì)阻塞其他事務(wù)的訪問(wèn),因此不會(huì)出現(xiàn)死鎖的情況。

缺點(diǎn)

  • 沖突處理復(fù)雜:由于樂(lè)觀鎖不會(huì)阻塞其他事務(wù),因此在提交時(shí)需要檢查數(shù)據(jù)是否被其他事務(wù)修改,如果發(fā)現(xiàn)沖突,需要回滾事務(wù)或重新嘗試操作,這增加了沖突處理的復(fù)雜性。
  • 數(shù)據(jù)一致性風(fēng)險(xiǎn):樂(lè)觀鎖假設(shè)并發(fā)沖突較少,因此可能存在數(shù)據(jù)一致性的風(fēng)險(xiǎn)。如果多個(gè)事務(wù)同時(shí)對(duì)同一數(shù)據(jù)進(jìn)行修改,可能會(huì)導(dǎo)致數(shù)據(jù)不一致的情況。
  • 需要額外字段:為了實(shí)現(xiàn)樂(lè)觀鎖,通常需要在數(shù)據(jù)表中添加額外的版本號(hào)或時(shí)間戳字段,這增加了存儲(chǔ)空間的需求。
  • 處理不當(dāng)造成死循環(huán)風(fēng)險(xiǎn):在大多數(shù)業(yè)務(wù)中樂(lè)觀鎖更新失敗都會(huì)進(jìn)行自旋,如果沒(méi)有控制好自旋退出邏輯可能會(huì)造成遞歸死循環(huán)問(wèn)題。

四、樂(lè)觀鎖與悲觀鎖使用示例

這里舉例會(huì)以操作數(shù)據(jù)庫(kù)實(shí)現(xiàn)樂(lè)觀鎖與悲觀鎖示例,在實(shí)際開(kāi)發(fā)中一般在操作數(shù)據(jù)庫(kù)時(shí)經(jīng)常會(huì)使用到樂(lè)觀鎖與悲觀鎖的實(shí)現(xiàn)思路來(lái)確保數(shù)據(jù)一致性問(wèn)題,這里會(huì)以一個(gè)更新用戶錢(qián)包舉例。

用戶錢(qián)包表

CREATE TABLE `customer_wallet` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `customer_id` bigint(20) DEFAULT NULL COMMENT '客戶ID',
  `balance_amount` bigint(20) DEFAULT NULL COMMENT '剩余金額',
  `version` bigint(20) DEFAULT '1' COMMENT '版本鎖',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_customer_id` (`customer_id`)
) COMMENT='客戶錢(qián)包信息';

4.1、悲觀鎖實(shí)現(xiàn)更新用戶錢(qián)包示例

這里提供一個(gè)使用悲觀鎖扣減錢(qián)包余額的示例,在第一次查詢時(shí)添加for update操作,那么其它線程進(jìn)入該方法時(shí)則會(huì)阻塞等待上一個(gè)方法事務(wù)提交才能繼續(xù)執(zhí)行,在這整個(gè)方法中都是線程安全的,這就是常見(jiàn)的結(jié)合數(shù)據(jù)庫(kù)實(shí)現(xiàn)悲觀鎖更新數(shù)據(jù)的示例,所有線程都必須排隊(duì)串行更新數(shù)據(jù)。

    @Transactional(rollbackFor = Exception.class)
    public boolean pessimisticLockSubAmount(Long customerId, Long happenAmount) {
        // 1、查詢用戶錢(qián)包 - 并且添加for update 鎖,這里customer_id字段添加了索引最終鎖定的還是索引定義行的ID,和直接使用ID區(qū)別不大
        // 這段代碼相當(dāng)于 select * from customer_wallet where customer_id = ? for update
        CustomerWallet customerWallet = lambdaQuery()
                .eq(CustomerWallet::getCustomerId, customerId)
                .last("for update")
                .one();
        if(customerWallet == null){
            throw new RuntimeException("用戶錢(qián)包不存在");
        }
        // 2、校驗(yàn)用戶余額是否足夠
        Long balanceAmount = customerWallet.getBalanceAmount() - happenAmount;
        if(balanceAmount < 0){
            throw new RuntimeException("用戶余額不足");
        }
        // 3、更新錢(qián)包余額 update customer_wallet set balance_amount = ? where id = ?
        boolean update = lambdaUpdate()
                .eq(CustomerWallet::getId, customerWallet.getId())
                .set(CustomerWallet::getBalanceAmount, balanceAmount)
                .update();
        if(!update){
            throw new RuntimeException("錢(qián)包更新失敗");
        }
        // 4、添加余額明細(xì)
        addWalletDetail(customerWallet.getId(),2,happenAmount,balanceAmount);
        return update;
    }

4.2、樂(lè)觀鎖實(shí)現(xiàn)更新用戶錢(qián)包示例1

使用樂(lè)觀鎖更新數(shù)據(jù)時(shí),執(zhí)行更新語(yǔ)句時(shí)通過(guò)判斷version是否有變動(dòng)來(lái)確認(rèn)數(shù)據(jù)是否有過(guò)變更,如果數(shù)據(jù)庫(kù)當(dāng)前version值和查詢出來(lái)的version值相等則代表數(shù)據(jù)沒(méi)有變更可以更新,因?yàn)閿?shù)據(jù)庫(kù)指定ID更新某一行數(shù)據(jù)時(shí)是在數(shù)據(jù)庫(kù)層面會(huì)添加行鎖,確保只能有一個(gè)事務(wù)進(jìn)行這行數(shù)據(jù)更新,這樣就保證了數(shù)據(jù)的一致性。

    @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public boolean subAmount(Long customerId, Long happenAmount) {
        // 1、獲取用戶錢(qián)包
        CustomerWallet customerWallet = lambdaQuery().eq(CustomerWallet::getCustomerId, customerId).one();
        if (customerWallet == null) {
            throw new RuntimeException("用戶錢(qián)包不存在");
        }
        // 2、判斷用戶余額是否足夠
        Long balanceAmount = customerWallet.getBalanceAmount() - happenAmount;
        if(balanceAmount < 0){
            throw new RuntimeException("用戶余額不足");
        }
        // 3、進(jìn)行樂(lè)觀鎖更新 
        // 這段代碼相當(dāng)于 update customer_wallet set balance_amount = ?, version = ? where id = ? and version = ?
        boolean update = lambdaUpdate()
                .eq(CustomerWallet::getId, customerWallet.getId())
                .eq(CustomerWallet::getVersion, customerWallet.getVersion())
                .set(CustomerWallet::getBalanceAmount, balanceAmount)
                .set(CustomerWallet::getVersion, customerWallet.getVersion() + 1)
                .update();
        if(!update){
            log.info("樂(lè)觀鎖更新失敗,開(kāi)始自旋");
            return subAmount(customerId,happenAmount);
        }
        // 4、添加余額明細(xì)
        addWalletDetail(customerWallet.getId(),2,happenAmount,balanceAmount);
        return update;
    }

PS:注意,在使用樂(lè)觀鎖更新數(shù)據(jù)時(shí),事務(wù)隔離級(jí)別必須設(shè)置為READ_COMMITTED,在最后注意事項(xiàng)中會(huì)進(jìn)行分析。

4.3、樂(lè)觀鎖實(shí)現(xiàn)更新用戶錢(qián)包示例2

樂(lè)觀鎖實(shí)現(xiàn)更新用戶錢(qián)包示例1中使用了一個(gè)version字段來(lái)作為樂(lè)觀鎖更新的標(biāo)記,其實(shí)對(duì)于這種更新錢(qián)包的業(yè)務(wù)想使用樂(lè)觀鎖完全沒(méi)有必要單獨(dú)加一個(gè)version字段,可以直接使用余額字段作為這個(gè)樂(lè)觀鎖的比較字段,因?yàn)槲覀冞@里擬定的是用戶余額需要足夠才能支付,那么在更新錢(qián)包時(shí)判斷一下當(dāng)前余額是否大于等于所需金額,如果滿足調(diào)整則

    @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public boolean subAmountV2(Long customerId, Long happenAmount) {
        // 1、獲取用戶錢(qián)包
        CustomerWallet customerWallet = lambdaQuery().eq(CustomerWallet::getCustomerId, customerId).one();
        if (customerWallet == null) {
            throw new RuntimeException("用戶錢(qián)包不存在");
        }

        // 2、直接使用余額作為樂(lè)觀鎖更新依據(jù)進(jìn)行樂(lè)觀鎖更新
        // 這段代碼相當(dāng)于 update customer_wallet set balance_amount = balance_amount + ? where id = ? and balance_amount >= ?
        boolean update = lambdaUpdate()
                .eq(CustomerWallet::getId, customerWallet.getId())
                .ge(CustomerWallet::getBalanceAmount, happenAmount)
                .setSql("balance_amount = balance_amount - "+happenAmount)
                .update();
        if(!update){
            log.info("樂(lè)觀鎖更新失敗,用戶余額不足");
            throw new RuntimeException("用戶余額不足");
        }
        // 3、添加余額明細(xì) 注意這里需要從新查詢一次數(shù)據(jù)
        CustomerWallet customerWalletNew = lambdaQuery().eq(CustomerWallet::getCustomerId, customerId).one();
        addWalletDetail(customerWallet.getId(),2,happenAmount,customerWalletNew.getBalanceAmount());
        return update;
    }

PS:注意,在使用樂(lè)觀鎖更新數(shù)據(jù)時(shí),事務(wù)隔離級(jí)別必須設(shè)置為READ_COMMITTED,在最后注意事項(xiàng)中會(huì)進(jìn)行分析。

五、注意事項(xiàng)

在使用樂(lè)觀鎖更新數(shù)據(jù)時(shí)要注意一個(gè)事務(wù)隔離級(jí)別的問(wèn)題,我這里使用的是READ COMMITTED(讀已提交),如果使用的是REPEATABLE READ(可重復(fù)讀)會(huì)存在兩個(gè)問(wèn)題,分別對(duì)應(yīng)4.2 和 4.3中的示例。

  • 在4.2示例中通過(guò)version值來(lái)實(shí)現(xiàn)樂(lè)觀鎖更新,如果這里使用的事務(wù)隔離級(jí)別為REPEATABLE READ(可重復(fù)讀),那么在樂(lè)觀鎖沖突更新失敗自旋時(shí)因?yàn)镸VCC機(jī)制查詢到的數(shù)據(jù)會(huì)是一個(gè)副本值,就算別的事務(wù)更新成功了讀取到的version都是歷史值,這樣會(huì)導(dǎo)致死循環(huán)遞歸最后棧溢出。
  • 在4.3示例中采用余額這樣的字段進(jìn)行判斷更新,因?yàn)镸ySQL的更新數(shù)據(jù)采用的是當(dāng)前讀,這里其實(shí)無(wú)論使用REPEATABLE READ(可重復(fù)讀)還是READ COMMITTED(讀已提交)事務(wù)隔離級(jí)別都不會(huì)存在死循環(huán)問(wèn)題,但是如果鎖沖突頻繁在使用REPEATABLE READ(可重復(fù)讀)事務(wù)隔離級(jí)別時(shí)可能會(huì)出現(xiàn)鎖持有時(shí)間過(guò)長(zhǎng)問(wèn)題,因?yàn)樵?code>REPEATABLE READ事務(wù)隔離級(jí)別下,在一個(gè)事務(wù)中執(zhí)行一個(gè)更新語(yǔ)句,就算where id=1 and balance_amount >= 100 這樣的條件不成立,也會(huì)將這一行數(shù)據(jù)進(jìn)行鎖定,需要等待事務(wù)提交或回滾才會(huì)釋放鎖,也就是說(shuō)在自旋時(shí)其它事務(wù)想要更新數(shù)據(jù)等待時(shí)間會(huì)變長(zhǎng)影響系統(tǒng)吞吐量,而使用READ COMMITTED事務(wù)隔離級(jí)別當(dāng)where中條件不成立更新失敗時(shí)不會(huì)持有鎖,也就是說(shuō)事務(wù)A在更新失敗自旋時(shí)事務(wù)B也是可以進(jìn)行更新的,而不需要等待事務(wù)A自旋更新成功后才能進(jìn)行更新,這樣能提高系統(tǒng)吞吐量。

到此這篇關(guān)于java中樂(lè)觀鎖與悲觀鎖區(qū)別及使用場(chǎng)景分析的文章就介紹到這了,更多相關(guān)java 樂(lè)觀鎖與悲觀鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • java匿名內(nèi)部類(lèi)實(shí)例簡(jiǎn)析

    java匿名內(nèi)部類(lèi)實(shí)例簡(jiǎn)析

    匿名類(lèi)是不能有名稱的類(lèi),所以沒(méi)辦法引用它們,必須在創(chuàng)建時(shí),作為new語(yǔ)句的一部分來(lái)聲明它們,需要了解更多的可以參考本文
    2012-11-11
  • SpringBoot多模塊項(xiàng)目創(chuàng)建和初始化問(wèn)題

    SpringBoot多模塊項(xiàng)目創(chuàng)建和初始化問(wèn)題

    本文詳細(xì)介紹了使用SpringBoot框架創(chuàng)建一個(gè)包含數(shù)據(jù)庫(kù)操作、MyBatis-Plus、Knife4j、HTTP請(qǐng)求響應(yīng)等的Java Web項(xiàng)目的步驟和配置方法,內(nèi)容涵蓋創(chuàng)建項(xiàng)目結(jié)構(gòu)、配置數(shù)據(jù)庫(kù)連接、添加依賴、編寫(xiě)接口、處理異常、序列化和反序列化、配置接口文檔等等內(nèi)容
    2026-05-05
  • 如何在Java中使用支付寶SDK來(lái)獲取用戶的OpenID

    如何在Java中使用支付寶SDK來(lái)獲取用戶的OpenID

    在支付寶開(kāi)放平臺(tái)中,獲取用戶的OpenID通常是在用戶授權(quán)后通過(guò)支付寶的OAuth 2.0授權(quán)流程實(shí)現(xiàn)的,以下是一個(gè)基本的步驟說(shuō)明,以及如何在Java中使用支付寶SDK來(lái)獲取用戶的OpenID
    2024-08-08
  • SpringBoot中項(xiàng)目結(jié)構(gòu)的項(xiàng)目實(shí)踐

    SpringBoot中項(xiàng)目結(jié)構(gòu)的項(xiàng)目實(shí)踐

    SpringBoot項(xiàng)目結(jié)構(gòu)遵循Maven或Gradle的標(biāo)準(zhǔn)目錄結(jié)構(gòu),融入了SpringBoot的特定約定,本文就來(lái)介紹一下SpringBoot中項(xiàng)目結(jié)構(gòu)的項(xiàng)目,感興趣的可以了解一下
    2025-03-03
  • 如何使用Docker部署Java項(xiàng)目

    如何使用Docker部署Java項(xiàng)目

    在接觸了docker后,干什么都想用docker來(lái)弄,這篇文章主要給大家介紹了關(guān)于如何使用Docker部署Java項(xiàng)目的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • 將JavaDoc注釋生成API文檔的操作

    將JavaDoc注釋生成API文檔的操作

    這篇文章主要介紹了將JavaDoc注釋生成API文檔的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java組件FileUpload上傳文件實(shí)現(xiàn)代碼

    Java組件FileUpload上傳文件實(shí)現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了Java組件FileUpload上傳文件實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-06-06
  • springboot配合Thymeleaf完美實(shí)現(xiàn)遍歷功能

    springboot配合Thymeleaf完美實(shí)現(xiàn)遍歷功能

    Thymeleaf顯然是一個(gè)開(kāi)發(fā)頁(yè)面的技術(shù),現(xiàn)在各種前端技術(shù)層出不窮,比如現(xiàn)在主流的Vue、React、AngularJS等。這篇文章主要介紹了springboot配合Thymeleaf完美實(shí)現(xiàn)遍歷,需要的朋友可以參考下
    2021-09-09
  • 詳解JAVA中獲取文件MD5值的四種方法

    詳解JAVA中獲取文件MD5值的四種方法

    這篇文章主要介紹了JAVA中獲取文件MD5值的四種方法,獲取文件MD5值主要分為三個(gè)步驟,第一步獲取文件的byte信息,第二步通過(guò)MessageDigest類(lèi)進(jìn)行MD5加密,第三步轉(zhuǎn)換成16進(jìn)制的MD5碼值,需要的朋友可以參考下
    2022-08-08
  • spring cloud-zuul的Filter使用詳解

    spring cloud-zuul的Filter使用詳解

    這篇文章主要介紹了spring cloud-zuul的Filter使用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01

最新評(píng)論

黄大仙区| 昌邑市| 武宣县| 保德县| 柘城县| 兴安盟| 九寨沟县| 高安市| 营口市| 赤峰市| 禄劝| 莱州市| 新泰市| 阜阳市| 兴仁县| 扎囊县| 米林县| 蓬安县| 旌德县| 芜湖县| 肥东县| 平和县| 松溪县| 昔阳县| 广汉市| 丁青县| 额尔古纳市| 庆安县| 和政县| 剑阁县| 昔阳县| 拉孜县| 清丰县| 呼图壁县| 北川| 交口县| 荣成市| 青铜峡市| 格尔木市| 灵石县| 大连市|