亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot如何使用@Cacheable進(jìn)行緩存與取值

 更新時(shí)間:2022年08月16日 17:04:31   作者:弄個(gè)昵稱  
這篇文章主要介紹了SpringBoot如何使用@Cacheable進(jìn)行緩存與取值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

使用@Cacheable進(jìn)行緩存與取值

1. @Cacheable的作用

緩存使用步驟:@Cacheable這個(gè)注解,用它就是為了使用緩存的。所以我們可以先說一下緩存的使用步驟:

開啟基于注解的緩存,使用 @EnableCaching 標(biāo)識(shí)在 SpringBoot 的主啟動(dòng)類上。

標(biāo)注緩存注解即可

第一步:開啟基于注解的緩存,使用 @EnableCaching 標(biāo)注在 springboot 主啟動(dòng)類上

//開啟基于注解的緩存
@EnableCaching ??
@EnableRyFeignClients
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class ZfjgAuthApplication {
? ? public static void main(String[] args) {
? ? ? ? SpringApplication.run(ZfjgAuthApplication.class, args);
? ? }
}

第二步:標(biāo)注緩存注解

@Repository
public interface DeviceMapper {
? ? @Cacheable(cacheNames = "DeviceDO.deviceId")
? ? DeviceDO get(String deviceId);
? ? @CacheEvict(cacheNames = "DeviceDO.deviceId", key = "#record.deviceId")
? ? int insert(DeviceDO record);
}

注:這里使用 @Cacheable 注解就可以將運(yùn)行結(jié)果緩存,以后查詢相同的數(shù)據(jù),直接從緩存中取,不需要調(diào)用方法。

2.常用屬性說明

下面介紹一下 @Cacheable 這個(gè)注解常用的幾個(gè)屬性:

  • cacheNames/value:用來指定緩存組件的名字
  • key:緩存數(shù)據(jù)時(shí)使用的 key,可以用它來指定。默認(rèn)是使用方法參數(shù)的值。(這個(gè) key 你可以使用 spEL 表達(dá)式來編寫)
  • keyGenerator:key 的生成器。 key 和 keyGenerator 二選一使用
  • cacheManager:可以用來指定緩存管理器。從哪個(gè)緩存管理器里面獲取緩存。
  • condition:可以用來指定符合條件的情況下才緩存
  • unless:否定緩存。當(dāng) unless 指定的條件為 true ,方法的返回值就不會(huì)被緩存。當(dāng)然你也可以獲取到結(jié)果進(jìn)行判斷。(通過 #result 獲取方法結(jié)果)
  • sync:是否使用異步模式。

SpringBoot中Cacheable使用說明

功能說明

@Cacheable 注解在方法上,表示該方法的返回結(jié)果是可以緩存的。也就是說,該方法的返回結(jié)果會(huì)放在緩存中,以便于以后使用相同的參數(shù)調(diào)用該方法時(shí),會(huì)返回緩存中的值,而不會(huì)實(shí)際執(zhí)行該方法。

注意,這里強(qiáng)調(diào)了一點(diǎn):參數(shù)相同。這一點(diǎn)應(yīng)該是很容易理解的,因?yàn)榫彺娌魂P(guān)心方法的執(zhí)行邏輯,它能確定的是:對(duì)于同一個(gè)方法,如果參數(shù)相同,那么返回結(jié)果也是相同的。但是如果參數(shù)不同,緩存只能假設(shè)結(jié)果是不同的,所以對(duì)于同一個(gè)方法,你的程序運(yùn)行過程中,使用了多少種參數(shù)組合調(diào)用過該方法,理論上就會(huì)生成多少個(gè)緩存的 key(當(dāng)然,這些組合的參數(shù)指的是與生成 key 相關(guān)的)。下面來了解一下 @Cacheable 的一些參數(shù):

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
    @AliasFor("cacheNames")
    String[] value() default {};
    @AliasFor("value")
    String[] cacheNames() default {};
    String key() default "";
    String keyGenerator() default "";
    String cacheManager() default "";
    String cacheResolver() default "";
    String condition() default "";
    String unless() default "";
    boolean sync() default false;
}

1. cacheNames & value

@Cacheable 提供兩個(gè)參數(shù)來指定緩存名:value、cacheNames,二者選其一即可。這是 @Cacheable 最簡(jiǎn)單的用法示例:

@Override
@Cacheable("menu")
public Menu findById(String id) {
    Menu menu = this.getById(id);
    if (menu != null){
        System.out.println("menu.name = " + menu.getName());
    }
    return menu;
}

在這個(gè)例子中,findById 方法與一個(gè)名為 menu 的緩存關(guān)聯(lián)起來了。調(diào)用該方法時(shí),會(huì)檢查 menu 緩存,如果緩存中有結(jié)果,就不會(huì)去執(zhí)行方法了。

2. 關(guān)聯(lián)多個(gè)緩存名

其實(shí),按照官方文檔,@Cacheable 支持同一個(gè)方法關(guān)聯(lián)多個(gè)緩存。這種情況下,當(dāng)執(zhí)行方法之前,這些關(guān)聯(lián)的每一個(gè)緩存都會(huì)被檢查,而且只要至少其中一個(gè)緩存命中了,那么這個(gè)緩存中的值就會(huì)被返回。

示例:

@Override
    @Cacheable({"menu", "menuById"})
    public Menu findById(String id) {
        Menu menu = this.getById(id);
        if (menu != null){
            System.out.println("menu.name = " + menu.getName());
        }
        return menu;
    }
---------
@GetMapping("/findById/{id}")
public Menu findById(@PathVariable("id")String id){
    Menu menu0 = menuService.findById("fe278df654adf23cf6687f64d1549c0a");
    Menu menu2 = menuService.findById("fb6106721f289ebf0969565fa8361c75");
    return menu0;
}

為了直觀起見,直接將 id 參數(shù)寫到代碼里?,F(xiàn)在,我們來測(cè)試一下,看一下結(jié)果:

3. key & keyGenerator

一個(gè)緩存名對(duì)應(yīng)一個(gè)被注解的方法,但是一個(gè)方法可能傳入不同的參數(shù),那么結(jié)果也就會(huì)不同,這應(yīng)該如何區(qū)分呢?這就需要用到 key 。在 spring 中,key 的生成有兩種方式:顯式指定和使用 keyGenerator 自動(dòng)生成。

3.1 KeyGenerator 自動(dòng)生成

當(dāng)我們?cè)诼暶?@Cacheable 時(shí)不指定 key 參數(shù),則該緩存名下的所有 key 會(huì)使用 KeyGenerator 根據(jù)參數(shù) 自動(dòng)生成。spring 有一個(gè)默認(rèn)的 SimpleKeyGenerator ,在 spring boot 自動(dòng)化配置中,這個(gè)會(huì)被默認(rèn)注入。生成規(guī)則如下:

  • 如果該緩存方法沒有參數(shù),返回 SimpleKey.EMPTY ;
  • 如果該緩存方法有一個(gè)參數(shù),返回該參數(shù)的實(shí)例 ;
  • 如果該緩存方法有多個(gè)參數(shù),返回一個(gè)包含所有參數(shù)的 SimpleKey ;

默認(rèn)的 key 生成器要求參數(shù)具有有效的 hashCode() 和 equals() 方法實(shí)現(xiàn)。另外,keyGenerator 也支持自定義, 并通過 keyGenerator 來指定。關(guān)于 KeyGenerator 這里不做詳細(xì)介紹,有興趣的話可以去看看源碼,其實(shí)就是使用 hashCode 進(jìn)行加乘運(yùn)算。跟 String 和 ArrayList 的 hash 計(jì)算類似。

3.2 顯式指定 key

相較于使用 KeyGenerator 生成,spring 官方更推薦顯式指定 key 的方式,即指定 @Cacheable 的 key 參數(shù)。

即便是顯式指定,但是 key 的值還是需要根據(jù)參數(shù)的不同來生成,那么如何實(shí)現(xiàn)動(dòng)態(tài)拼接呢?SpEL(Spring Expression Language,Spring 表達(dá)式語言) 能做到這一點(diǎn)。下面是一些使用 SpEL 生成 key 的例子。

@Override
    @Cacheable(value = {"menuById"}, key = "#id")
    public Menu findById(String id) {
        Menu menu = this.getById(id);
        if (menu != null){
            System.out.println("menu.name = " + menu.getName());
        }
        return menu;
    }
    @Override
    @Cacheable(value = {"menuById"}, key = "'id-' + #menu.id")
    public Menu findById(Menu menu) {
        return menu;
    }
    @Override
    @Cacheable(value = {"menuById"}, key = "'hash' + #menu.hashCode()")
    public Menu findByHash(Menu menu) {
        return menu;
    }

官方說 key 和 keyGenerator 參數(shù)是互斥的,同時(shí)指定兩個(gè)會(huì)導(dǎo)致異常。

4. cacheManager & cacheResolver

CacheManager,緩存管理器是用來管理(檢索)一類緩存的。通常來講,緩存管理器是與緩存組件類型相關(guān)聯(lián)的。我們知道,spring 緩存抽象的目的是為使用不同緩存組件類型提供統(tǒng)一的訪問接口,以向開發(fā)者屏蔽各種緩存組件的差異性。那么 CacheManager 就是承擔(dān)了這種屏蔽的功能。spring 為其支持的每一種緩存的組件類型提供了一個(gè)默認(rèn)的 manager,如:RedisCacheManager 管理 redis 相關(guān)的緩存的檢索、EhCacheManager 管理 ehCache 相關(guān)的緩等。

CacheResolver,緩存解析器是用來管理緩存管理器的,CacheResolver 保持一個(gè) cacheManager 的引用,并通過它來檢索緩存。CacheResolver 與 CacheManager 的關(guān)系有點(diǎn)類似于 KeyGenerator 跟 key。spring 默認(rèn)提供了一個(gè) SimpleCacheResolver,開發(fā)者可以自定義并通過 @Bean 來注入自定義的解析器,以實(shí)現(xiàn)更靈活的檢索。

大多數(shù)情況下,我們的系統(tǒng)只會(huì)配置一種緩存,所以我們并不需要顯式指定 cacheManager 或者 cacheResolver。但是 spring 允許我們的系統(tǒng)同時(shí)配置多種緩存組件,這種情況下,我們需要指定。指定的方式是使用 @Cacheable 的 cacheManager 或者 cacheResolver 參數(shù)。

按照官方文檔,cacheManager 和 cacheResolver 是互斥參數(shù),同時(shí)指定兩個(gè)可能會(huì)導(dǎo)致異常。

5. sync

是否同步,true/false。在一個(gè)多線程的環(huán)境中,某些操作可能被相同的參數(shù)并發(fā)地調(diào)用,這樣同一個(gè) value 值可能被多次計(jì)算(或多次訪問 db),這樣就達(dá)不到緩存的目的。針對(duì)這些可能高并發(fā)的操作,我們可以使用 sync 參數(shù)來告訴底層的緩存提供者將緩存的入口鎖住,這樣就只能有一個(gè)線程計(jì)算操作的結(jié)果值,而其它線程需要等待,這樣就避免了 n-1 次數(shù)據(jù)庫(kù)訪問。

sync = true 可以有效的避免緩存擊穿的問題。

6. condition

調(diào)用前判斷,緩存的條件。有時(shí)候,我們可能并不想對(duì)一個(gè)方法的所有調(diào)用情況進(jìn)行緩存,我們可能想要根據(jù)調(diào)用方法時(shí)候的某些參數(shù)值,來確定是否需要將結(jié)果進(jìn)行緩存或者從緩存中取結(jié)果。比如當(dāng)我根據(jù)年齡查詢用戶的時(shí)候,我只想要緩存年齡大于 35 的查詢結(jié)果。那么 condition 能實(shí)現(xiàn)這種效果。

condition 接收一個(gè)結(jié)果為 true 或 false 的表達(dá)式,表達(dá)式同樣支持 SpEL 。如果表達(dá)式結(jié)果為 true,則調(diào)用方法時(shí)會(huì)執(zhí)行正常的緩存邏輯(查緩存-有就返回-沒有就執(zhí)行方法-方法返回不空就添加緩存);否則,調(diào)用方法時(shí)就好像該方法沒有聲明緩存一樣(即無論傳入了什么參數(shù)或者緩存中有些什么值,都會(huì)執(zhí)行方法,并且結(jié)果不放入緩存)。下面舉個(gè)例子:

我們看一下數(shù)據(jù)庫(kù),以這兩條數(shù)據(jù)為例:

  

我們首先定義一個(gè)帶條件的緩存方法:

@Override
    @Cacheable(value = {"menuById"}, key = "#id", condition = "#conditionValue > 1")
    public Menu findById(String id, Integer conditionValue) {
        Menu menu = this.getById(id);
        if (menu != null){
            System.out.println("menu.name = " + menu.getName());
        }
        return menu;
    }

然后分兩種情況調(diào)用(為了直觀可見,直接將 id 寫在代碼中):

@GetMapping("/findById/{id}")
    public Menu findById(@PathVariable("id")String id){
        Menu menu0 = menuService.findById("fe278df654adf23cf6687f64d1549c0a", 0);
        Menu menu2 = menuService.findById("fb6106721f289ebf0969565fa8361c75", 2);
        return menu0;
    }

可以看到,兩次請(qǐng)求都執(zhí)行方法(因?yàn)樵瓉砭彺嬷卸紱]有數(shù)據(jù)),但是只有“微服務(wù)測(cè)試2”緩存了。這說明,只有滿足 condition 條件的調(diào)用,結(jié)果才會(huì)被緩存。接下來我們?cè)僬?qǐng)求一遍,看下結(jié)果和打?。?/p>

可以看到,“微服務(wù)測(cè)試2”由于已經(jīng)有了緩存,所以沒有再執(zhí)行方法體。而“微服務(wù)測(cè)試0”又一次執(zhí)行了。

7. unless

執(zhí)行后判斷,不緩存的條件。unless 接收一個(gè)結(jié)果為 true 或 false 的表達(dá)式,表達(dá)式支持 SpEL。當(dāng)結(jié)果為 true 時(shí),不緩存。舉個(gè)例子:

我們先清除 redis 中的數(shù)據(jù)。然后看看 mysql 中的數(shù)據(jù):

  

然后編寫一個(gè)緩存方法(在該方法中,result代表方法的返回值。關(guān)于):

@Override
    @Cacheable(value = {"menuById"}, key = "#id", unless = "#result.type == 'folder'")
    public Menu findById(String id) {
        Menu menu = this.getById(id);
        if (menu != null){
            System.out.println("menu.name = " + menu.getName());
        }
        return menu;
    }

然后調(diào)用該方法:

@GetMapping("/findById/{id}")
    public Menu findById(@PathVariable("id")String id){
        Menu menu0 = menuService.findById("fe278df654adf23cf6687f64d1549c0a");
        Menu menu2 = menuService.findById("fb6106721f289ebf0969565fa8361c75");
        return menu0;
    }

可以看到,兩次都執(zhí)行了方法體(其實(shí),unless 條件就是在方法執(zhí)行完畢后調(diào)用,所以它不會(huì)影響方法的執(zhí)行),但是結(jié)果只有 menu.type = ‘page’ 的緩存了,說明 unless 參數(shù)生效了。

8. condition VS unless ?

既然 condition 和 unless 都能決定是否進(jìn)行緩存,那么同時(shí)指定這兩個(gè)參數(shù)并且結(jié)果相沖突的時(shí)候,會(huì)怎么樣呢?我們來試一試。

首先清除 redis 數(shù)據(jù),然后在緩存方法上加上 condition=“true”,如:

@Override
    @Cacheable(value = {"menuById"}, key = "#id", condition = "true", unless = "#result.type == 'folder'")
    public Menu findById(String id) {
        Menu menu = this.getById(id);
        if (menu != null){
            System.out.println("menu.name = " + menu.getName());
        }
        return menu;
    }

其它代碼不變,我們來看一下緩存結(jié)果和打?。?/p>

可以看到,雖然兩次調(diào)用都執(zhí)行了,但是,type=‘folder’ 的還是被排除了。說明這種情況下,unless 比 condition 優(yōu)先級(jí)要高。接下來我們把 condition=“false”,再來試試,結(jié)果:

可以看到,兩次調(diào)用的結(jié)果都沒有緩存。說明在這種情況下,condition 比 unless 的優(yōu)先級(jí)高??偨Y(jié)起來就是:

  • condition 不指定相當(dāng)于 true,unless 不指定相當(dāng)于 false
  • condition = false,一定不會(huì)緩存;
  • condition = true,且 unless = true,不緩存;
  • condition = true,且 unless = false,緩存;

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring定時(shí)任務(wù)@Scheduled注解(cron表達(dá)式fixedRate?fixedDelay)

    Spring定時(shí)任務(wù)@Scheduled注解(cron表達(dá)式fixedRate?fixedDelay)

    這篇文章主要為大家介紹了Spring定時(shí)任務(wù)@Scheduled注解(cron表達(dá)式fixedRate?fixedDelay)使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Springboot死信隊(duì)列?DLX?配置和使用思路分析

    Springboot死信隊(duì)列?DLX?配置和使用思路分析

    死信隊(duì)列簡(jiǎn)稱就是DLX,死信交換機(jī)和死信隊(duì)列和普通的沒有區(qū)別,當(dāng)消息成為死信后,如果該隊(duì)列綁定了死信交換機(jī),則消息會(huì)被死信交換機(jī)重新路由到死信隊(duì)列,本文給大家介紹Springboot死信隊(duì)列?DLX的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2022-03-03
  • Java 如何快速實(shí)現(xiàn)一個(gè)連接池

    Java 如何快速實(shí)現(xiàn)一個(gè)連接池

    有沒有一個(gè)通用的庫(kù)可以快速實(shí)現(xiàn)一個(gè)線程池呢?得益于 Java 完善的生態(tài),前人們針對(duì)這種需要開發(fā)了一個(gè)通用庫(kù):Apache Commons Pool(下文簡(jiǎn)稱 ACP)。本質(zhì)上來說,ACP 庫(kù)提供的是管理對(duì)象池的通用能力,當(dāng)然也可以用來管理連接池了!
    2021-05-05
  • SpringBoot項(xiàng)目更換項(xiàng)目名稱的實(shí)現(xiàn)

    SpringBoot項(xiàng)目更換項(xiàng)目名稱的實(shí)現(xiàn)

    本文主要介紹了SpringBoot項(xiàng)目更換項(xiàng)目名稱,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • maven私服搭建的實(shí)現(xiàn)步驟

    maven私服搭建的實(shí)現(xiàn)步驟

    本文主要介紹了maven私服搭建的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Java中BigDecimal類的簡(jiǎn)單用法

    Java中BigDecimal類的簡(jiǎn)單用法

    這篇文章主要介紹了Java中BigDecimal類的簡(jiǎn)單用法,是Java應(yīng)用程序開發(fā)中非常實(shí)用的技巧,本文以實(shí)例形式對(duì)此進(jìn)行了簡(jiǎn)單的分析,需要的朋友可以參考下
    2014-09-09
  • IntelliJ?IDEA?2020.2.3永久破解激活教程(親測(cè)有效)

    IntelliJ?IDEA?2020.2.3永久破解激活教程(親測(cè)有效)

    intellij?idea?2022是一款市面上最好的JAVA?IDE編程工具,該工具支持git、svn、github等版本控制工具,整合了智能代碼助手、代碼自動(dòng)提示等功能,本教程給大家分享IDEA?2022最新永久激活碼,感興趣的朋友參考下吧
    2020-10-10
  • Java(TM) Platform SE binary 打開jar文件的操作

    Java(TM) Platform SE binary 打開jar文件的操作

    這篇文章主要介紹了Java(TM) Platform SE binary 打開jar文件的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 基于Java實(shí)現(xiàn)Avro文件讀寫功能

    基于Java實(shí)現(xiàn)Avro文件讀寫功能

    大家好,本篇文章主要講的是基于Java實(shí)現(xiàn)Avro文件讀寫功能,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-02-02
  • Java實(shí)現(xiàn)的Excel列號(hào)數(shù)字與字母互相轉(zhuǎn)換功能

    Java實(shí)現(xiàn)的Excel列號(hào)數(shù)字與字母互相轉(zhuǎn)換功能

    這篇文章主要介紹了Java實(shí)現(xiàn)的Excel列號(hào)數(shù)字與字母互相轉(zhuǎn)換功能,涉及java針對(duì)Excel相關(guān)數(shù)值與字符串操作技巧,需要的朋友可以參考下
    2018-03-03

最新評(píng)論