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

使用Spring Cache和Redis實(shí)現(xiàn)查詢數(shù)據(jù)緩存

 更新時(shí)間:2024年07月15日 08:57:02   作者:詩(shī)筠  
在現(xiàn)代應(yīng)用程序中,查詢緩存的使用已經(jīng)變得越來(lái)越普遍,它不僅能夠顯著提高系統(tǒng)的性能,還能提升用戶體驗(yàn),在這篇文章中,我們將探討緩存的基本概念、重要性以及如何使用Spring Cache和Redis實(shí)現(xiàn)查詢數(shù)據(jù)緩存,需要的朋友可以參考下

1. 前言

在現(xiàn)代應(yīng)用程序中,查詢緩存的使用已經(jīng)變得越來(lái)越普遍。它不僅能夠顯著提高系統(tǒng)的性能,還能提升用戶體驗(yàn)。緩存通過(guò)在內(nèi)存中存儲(chǔ)頻繁訪問(wèn)的數(shù)據(jù),減少對(duì)數(shù)據(jù)庫(kù)或其他存儲(chǔ)系統(tǒng)的訪問(wèn),從而加快數(shù)據(jù)讀取速度。在這篇文章中,我們將探討緩存的基本概念、重要性以及如何使用Spring Cache和Redis實(shí)現(xiàn)查詢數(shù)據(jù)緩存 。

2. 緩存

2.1 什么是緩存

緩存是一種臨時(shí)存儲(chǔ)機(jī)制,用于在內(nèi)存中保存頻繁訪問(wèn)的數(shù)據(jù)。它可以是硬件(如CPU緩存)或軟件(如應(yīng)用程序緩存)。緩存的主要目的是通過(guò)減少數(shù)據(jù)訪問(wèn)的延遲,提高系統(tǒng)的響應(yīng)速度。以下是緩存的一些關(guān)鍵特性:

  • 臨時(shí)性:緩存中的數(shù)據(jù)通常是臨時(shí)的,會(huì)在一段時(shí)間后失效或被替換。
  • 快速訪問(wèn):由于緩存數(shù)據(jù)存儲(chǔ)在內(nèi)存中,訪問(wèn)速度非??臁?/li>
  • 空間有限:緩存的存儲(chǔ)空間通常有限,因此需要有效的管理策略,如LRU(最近最少使用)策略。

2.2 使用緩存的好處

  1. 提高性能:緩存可以顯著減少數(shù)據(jù)讀取的時(shí)間,因?yàn)閮?nèi)存訪問(wèn)速度比硬盤或網(wǎng)絡(luò)存儲(chǔ)快很多。
  2. 減輕數(shù)據(jù)庫(kù)負(fù)載:緩存可以減少數(shù)據(jù)庫(kù)的查詢次數(shù),從而減輕數(shù)據(jù)庫(kù)的負(fù)載,提升整體系統(tǒng)的穩(wěn)定性和可擴(kuò)展性。
  3. 節(jié)省資源:通過(guò)減少對(duì)后端系統(tǒng)的訪問(wèn),緩存可以幫助節(jié)省帶寬和計(jì)算資源。
  4. 提高用戶體驗(yàn):快速的數(shù)據(jù)訪問(wèn)可以顯著提升用戶體驗(yàn),特別是在需要頻繁讀取數(shù)據(jù)的應(yīng)用場(chǎng)景中。

2.3 緩存的成本

  1. 內(nèi)存消耗:緩存需要占用系統(tǒng)的內(nèi)存資源,過(guò)多的緩存可能會(huì)影響其他應(yīng)用程序的性能。
  2. 數(shù)據(jù)一致性:緩存中的數(shù)據(jù)可能會(huì)與數(shù)據(jù)庫(kù)中的數(shù)據(jù)不一致,尤其是在數(shù)據(jù)頻繁更新的場(chǎng)景中。需要設(shè)計(jì)有效的緩存失效策略來(lái)保證數(shù)據(jù)的一致性。
  3. 復(fù)雜性增加:引入緩存機(jī)制會(huì)增加系統(tǒng)的復(fù)雜性,需要處理緩存的管理、更新和失效等問(wèn)題。
  4. 維護(hù)成本:緩存系統(tǒng)需要定期監(jiān)控和維護(hù),以確保其高效運(yùn)行。

2.4 Spring Cache和Redis的優(yōu)點(diǎn)

為了實(shí)現(xiàn)高效的數(shù)據(jù)緩存,Spring Boot提供了Spring Cache模塊,而Redis則是一個(gè)強(qiáng)大的緩存數(shù)據(jù)庫(kù)。結(jié)合使用Spring Cache和Redis,能夠充分發(fā)揮二者的優(yōu)點(diǎn),實(shí)現(xiàn)高效的數(shù)據(jù)緩存。

  • Spring Cache的優(yōu)點(diǎn)
    • 簡(jiǎn)化緩存操作:Spring Cache提供了一系列注解(如@Cacheable、@CachePut@CacheEvict),簡(jiǎn)化了緩存的使用,使開發(fā)者能夠?qū)W⒂跇I(yè)務(wù)邏輯。
    • 靈活的緩存管理:Spring Cache支持多種緩存提供者(如EhCache、Hazelcast、Redis等),可以根據(jù)具體需求選擇合適的緩存實(shí)現(xiàn)。
    • 透明的緩存機(jī)制:Spring Cache使得緩存操作對(duì)業(yè)務(wù)代碼透明,開發(fā)者無(wú)需關(guān)心緩存的具體實(shí)現(xiàn)細(xì)節(jié)。
  • Redis的優(yōu)點(diǎn)
    • 高性能:由于數(shù)據(jù)存儲(chǔ)在內(nèi)存中,Redis的讀寫速度非常快,能夠處理每秒數(shù)百萬(wàn)級(jí)別的請(qǐng)求。
    • 豐富的數(shù)據(jù)結(jié)構(gòu):Redis支持多種數(shù)據(jù)結(jié)構(gòu),如字符串、哈希、列表、集合、有序集合等,能夠滿足不同場(chǎng)景下的數(shù)據(jù)存儲(chǔ)需求。
    • 持久化支持:雖然Redis主要用于內(nèi)存存儲(chǔ),但它也提供了數(shù)據(jù)持久化的功能,可以將數(shù)據(jù)定期保存到磁盤,防止數(shù)據(jù)丟失。
    • 分布式支持:Redis支持主從復(fù)制、哨兵模式和集群模式,能夠?qū)崿F(xiàn)高可用性和數(shù)據(jù)的水平擴(kuò)展。
    • 靈活的過(guò)期策略:Redis支持為每個(gè)鍵設(shè)置過(guò)期時(shí)間,自動(dòng)刪除過(guò)期數(shù)據(jù),方便實(shí)現(xiàn)緩存失效策略。

3. Spring Cache基礎(chǔ)知識(shí)

在Spring Boot中,Spring Cache提供了一套簡(jiǎn)潔且強(qiáng)大的緩存抽象機(jī)制,幫助開發(fā)者輕松地將緩存集成到應(yīng)用程序中。以下是Spring Cache的一些核心概念和常用注解。

3.1 Spring Cache的核心概念

CacheManager

  • 定義CacheManager是Spring Cache的核心接口,負(fù)責(zé)管理多個(gè)緩存實(shí)例。它是緩存操作的入口點(diǎn),提供了獲取和操作緩存實(shí)例的方法。
  • 實(shí)現(xiàn):Spring提供了多種CacheManager實(shí)現(xiàn),如ConcurrentMapCacheManager、EhCacheCacheManagerRedisCacheManager等。不同的實(shí)現(xiàn)適用于不同的緩存存儲(chǔ)機(jī)制。

Cache

  • 定義Cache是緩存的具體實(shí)現(xiàn),負(fù)責(zé)存儲(chǔ)和檢索緩存數(shù)據(jù)。它提供了基本的緩存操作,如put、get、evict等。
  • 實(shí)現(xiàn):具體的Cache實(shí)現(xiàn)依賴于底層的緩存存儲(chǔ)機(jī)制,如內(nèi)存緩存、Redis緩存等。

3.2 Spring Cache的注解

3.2.1 SpEL表達(dá)式

因?yàn)镾pring Cache使用SpEL表達(dá)式來(lái)動(dòng)態(tài)生成緩存鍵,所以在學(xué)習(xí)Spring Cache的注解之前我們還要先簡(jiǎn)單了解一下SpEL表達(dá)式的語(yǔ)法,這部分可以先不看懂,在后面看注解的時(shí)候回來(lái)看即可。

SpEL表達(dá)式的語(yǔ)法類似于Java的表達(dá)式語(yǔ)法,支持以下幾種操作:

  1. 字面量
    • 數(shù)字:12.5
    • 字符串:'hello'"world"
    • 布爾值:truefalse
    • 空值:null
  2. 屬性和方法
    • 訪問(wèn)對(duì)象的屬性:#user.name
    • 調(diào)用對(duì)象的方法:#user.getName()
  3. 運(yùn)算符
    • 算術(shù)運(yùn)算:+-*/%
    • 比較運(yùn)算:==!=<><=>=
    • 邏輯運(yùn)算:&&||!
  4. 集合和數(shù)組
    • 訪問(wèn)集合元素:#users[0]
    • 集合操作:#users.size()#users.isEmpty()
  5. 條件運(yùn)算符
    • 三元運(yùn)算符:condition ? trueValue : falseValue
    • Elvis運(yùn)算符:expression ?: defaultValue
  6. 變量
    • 定義和使用變量:#variableName

接下來(lái)進(jìn)入Spring Cache注解的學(xué)習(xí):

3.2.2 @Cacheable

作用@Cacheable注解用于標(biāo)注需要緩存的方法。當(dāng)該方法被調(diào)用時(shí),Spring Cache會(huì)先檢查緩存中是否存在對(duì)應(yīng)的數(shù)據(jù)。如果存在,則直接返回緩存數(shù)據(jù);如果不存在,則執(zhí)行方法并將結(jié)果存入緩存。

示例

@RestController("/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;
    
    @Cacheable(value = "user", key = "#id")
    public User getUser(Long id) {
        // 獲取用戶的邏輯
        return userService.findById(id);
    }
}
  • 參數(shù)
    • value:指定緩存的名稱。
    • key:指定緩存的鍵,可以使用SpEL表達(dá)式。

3.2.3 @CachePut

  • 作用@CachePut注解用于標(biāo)注需要更新緩存的方法。即使緩存中已經(jīng)存在數(shù)據(jù),該方法仍然會(huì)執(zhí)行,并將結(jié)果更新到緩存中。
  • 示例
@RestController("/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;
    
    @CachePut(value = "user", key = "#user.id")
    public User updateUser(User user) {
        // 更新用戶的邏輯
        return userService.save(user);
    }
}
  • 參數(shù)
    • value:指定緩存的名稱。
    • key:指定緩存的鍵,可以使用SpEL表達(dá)式。

3.2.4 @CacheEvict

作用@CacheEvict注解用于標(biāo)注需要清除緩存的方法。當(dāng)該方法被調(diào)用時(shí),Spring Cache會(huì)清除對(duì)應(yīng)的緩存數(shù)據(jù)。

示例

@RestController("/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;
    
    @CacheEvict(value = "user", key = "#id")
    public void deleteUser(Long id) {
        // 刪除用戶的邏輯
        userService.deleteById(id);
    }
}
  • 參數(shù)
    • value:指定緩存的名稱。
    • key:指定緩存的鍵,可以使用SpEL表達(dá)式。
    • allEntries:如果設(shè)置為true,則清除緩存中的所有數(shù)據(jù)。

4. 實(shí)現(xiàn)查詢數(shù)據(jù)緩存

4.1 準(zhǔn)備工作 Redis安裝與配置:

  • Redis安裝與配置:

這里可以自行查找文章進(jìn)行安裝和配置,網(wǎng)上優(yōu)質(zhì)文章很多。

創(chuàng)建Product實(shí)體類:

@Data
@AllArgsConstructor
public class Product implements Serializable {

    private Long id;

    private String name;

    private Integer category;

    private String description;

    private Integer stock;

}

創(chuàng)建枚舉類ResultEnum

@Getter
public enum ResultEnum {

    /* 成功狀態(tài)碼 */
    SUCCESS(1, "操作成功!"),

    /* 錯(cuò)誤狀態(tài)碼 */
    FAIL(0, "操作失敗!"),

    /* 參數(shù)錯(cuò)誤:10001-19999 */
    PARAM_IS_INVALID(10001, "參數(shù)無(wú)效"),
    PARAM_IS_BLANK(10002, "參數(shù)為空"),
    PARAM_TYPE_BIND_ERROR(10003, "參數(shù)格式錯(cuò)誤"),
    PARAM_NOT_COMPLETE(10004, "參數(shù)缺失"),

    /* 用戶錯(cuò)誤:20001-29999*/
    USER_NOT_LOGGED_IN(20001, "用戶未登錄,請(qǐng)先登錄"),
    USER_LOGIN_ERROR(20002, "賬號(hào)不存在或密碼錯(cuò)誤"),
    USER_ACCOUNT_FORBIDDEN(20003, "賬號(hào)已被禁用"),
    USER_NOT_EXIST(20004, "用戶不存在"),
    USER_HAS_EXISTED(20005, "用戶已存在"),

    /* 系統(tǒng)錯(cuò)誤:40001-49999 */
    FILE_MAX_SIZE_OVERFLOW(40003, "上傳尺寸過(guò)大"),
    FILE_ACCEPT_NOT_SUPPORT(40004, "上傳文件格式不支持"),

    /* 數(shù)據(jù)錯(cuò)誤:50001-599999 */
    RESULT_DATA_NONE(50001, "數(shù)據(jù)未找到"),
    DATA_IS_WRONG(50002, "數(shù)據(jù)有誤"),
    DATA_ALREADY_EXISTED(50003, "數(shù)據(jù)已存在"),
    AUTH_CODE_ERROR(50004, "驗(yàn)證碼錯(cuò)誤"),


    /* 權(quán)限錯(cuò)誤:70001-79999 */
    PERMISSION_UNAUTHENTICATED(70001, "此操作需要登陸系統(tǒng)!"),

    PERMISSION_UNAUTHORIZED(70002, "權(quán)限不足,無(wú)權(quán)操作!"),

    PERMISSION_EXPIRE(70003, "登錄狀態(tài)過(guò)期!"),

    PERMISSION_TOKEN_EXPIRED(70004, "token已過(guò)期"),

    PERMISSION_LIMIT(70005, "訪問(wèn)次數(shù)受限制"),

    PERMISSION_TOKEN_INVALID(70006, "無(wú)效token"),

    PERMISSION_SIGNATURE_ERROR(70007, "簽名失敗");

    // 狀態(tài)碼
    int code;
    // 提示信息
    String message;

    ResultEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int code() {
        return code;
    }

    public String message() {
        return message;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

創(chuàng)建統(tǒng)一返回結(jié)果封裝類Result

@Data
@NoArgsConstructor
public class Result<T> implements Serializable {

    // 操作代碼
    Integer code;

    // 提示信息
    String message;

    // 結(jié)果數(shù)據(jù)
    T data;

    public Result(ResultEnum resultCode) {
        this.code = resultCode.code();
        this.message = resultCode.message();
    }

    public Result(ResultEnum resultCode, T data) {
        this.code = resultCode.code();
        this.message = resultCode.message();
        this.data = data;
    }
    public Result(String message) {
        this.message = message;
    }
    //成功返回封裝-無(wú)數(shù)據(jù)
    public static Result<String> success() {
        return new Result<String>(ResultEnum.SUCCESS);
    }
    //成功返回封裝-帶數(shù)據(jù)
    public static <T> Result<T> success(T data) {
        return new Result<T>(ResultEnum.SUCCESS, data);
    }
    //失敗返回封裝-使用默認(rèn)提示信息
    public static Result<String> error() {
        return new Result<String>(ResultEnum.FAIL);
    }
    //失敗返回封裝-使用返回結(jié)果枚舉提示信息
    public static Result<String> error(ResultEnum resultCode) {
        return new Result<String>(resultCode);
    }
    //失敗返回封裝-使用自定義提示信息
    public static Result<String> error(String message) {
        return new Result<String>(message);

    }
}

4.2 添加依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

4.3 修改配置文件

spring:
  data:
    redis:
      # Redis服務(wù)器地址
      host: ${shijun.redis.host}
      # Redis服務(wù)器端口
      port: ${shijun.redis.port}
      # Redis服務(wù)器認(rèn)證密碼
      password: ${shijun.redis.password}
      # Redis數(shù)據(jù)庫(kù)索引
      database: ${shijun.redis.database}

4.4 配置緩存管理器

/**
 * 配置類,用于設(shè)置緩存管理器及相關(guān)配置,以啟用緩存功能
 *
 * @author shijun
 * @date 2024/06/13
 */
@EnableCaching
@Configuration
public class CacheConfig extends CachingConfigurerSupport {

    /**
     * 配置Redis鍵的序列化方式
     *
     * @return StringRedisSerializer,用于序列化和反序列化Redis中的鍵
     */
    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

    /**
     * 配置Redis值的序列化方式
     *
     * @return GenericJackson2JsonRedisSerializer,使用Jackson庫(kù)以JSON格式序列化和反序列化Redis中的值
     */
    private RedisSerializer<Object> valueSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }

    /**
     * 緩存前綴,用于區(qū)分不同的緩存命名空間,一般以模塊名或者服務(wù)名命名,這里暫時(shí)寫cache
     */
    public static final String CACHE_PREFIX = "cache:";

    /**
     * 配置緩存管理器,使用Redis作為緩存后端
     *
     * @param redisConnectionFactory Redis連接工廠,用于創(chuàng)建Redis連接
     * @return RedisCacheManager,Redis緩存管理器實(shí)例
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 配置序列化,解決亂碼的問(wèn)題,設(shè)置緩存名稱的前綴和緩存條目的默認(rèn)過(guò)期時(shí)間
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                // 設(shè)置鍵的序列化器
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
                // 設(shè)置值的序列化器
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
                // 設(shè)置緩存名稱的前綴
                .computePrefixWith(name -> CACHE_PREFIX + name + ":")
                // 設(shè)置緩存條目的默認(rèn)過(guò)期時(shí)間為300秒
                .entryTtl(Duration.ofSeconds(300));

        // 創(chuàng)建非鎖定的Redis緩存寫入器
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(Objects.requireNonNull(redisConnectionFactory));

        // 返回Redis緩存管理器實(shí)例,使用上述配置
        return new RedisCacheManager(redisCacheWriter, config);
    }

}

分析:
StringRedisSerializer :使用 StringRedisSerializer 將緩存的鍵序列化為字符串。因?yàn)镽edis中的鍵通常是字符串類型,使用字符串序列化器可以確保鍵在Redis中以可讀的形式存儲(chǔ),便于調(diào)試和管理。

GenericJackson2JsonRedisSerializer :使用 GenericJackson2JsonRedisSerializer 將緩存的值序列化為JSON格式,可讀性高并且便于人工排查數(shù)據(jù)。

4.5 使用Spring Cache注解

由于我們的緩存的數(shù)據(jù)源來(lái)自于數(shù)據(jù)庫(kù),而數(shù)據(jù)庫(kù)的數(shù)據(jù)是會(huì)發(fā)生變化的,因此,如果當(dāng)數(shù)據(jù)庫(kù)中數(shù)據(jù)發(fā)生變化,而緩存卻沒(méi)有同步,此時(shí)就會(huì)有數(shù)據(jù)一致性問(wèn)題存在,在一些并發(fā)場(chǎng)景會(huì)出現(xiàn)問(wèn)題。

這里采用Cache Aside Pattern 即旁路緩存模式:緩存調(diào)用者在更新完數(shù)據(jù)庫(kù)后再去更新緩存,也稱之為雙寫方案。

image-20240613224855076

分析:

  • 應(yīng)用程序首先從緩存中查找數(shù)據(jù)。
  • 如果緩存命中,則直接返回緩存中的數(shù)據(jù)。
  • 如果緩存未命中,則從數(shù)據(jù)庫(kù)中讀取數(shù)據(jù),并將讀取到的數(shù)據(jù)寫入緩存,以便
  • 后續(xù)請(qǐng)求可以直接從緩存中獲取。
  • 寫流程

image-20240613221100300

分析:

  • 應(yīng)用程序首先更新數(shù)據(jù)庫(kù)中的數(shù)據(jù)。
  • 然后使緩存中的對(duì)應(yīng)數(shù)據(jù)失效
@Slf4j
@RestController("/products")
public class ProductController {


    /**
     * 根據(jù)ID獲取產(chǎn)品信息
     * 通過(guò)@Cacheable注解,當(dāng)請(qǐng)求的產(chǎn)品ID在緩存中存在時(shí),直接從緩存中獲取產(chǎn)品信息,減少數(shù)據(jù)庫(kù)查詢
     *
     * @param id 產(chǎn)品ID
     * @return 返回查詢結(jié)果,包含指定ID的產(chǎn)品信息
     */
    @GetMapping("/getProductById")
    @Cacheable(value = "productsCache", key = "#id")
    public Result<Product> getProductById(Long id) {
        // 當(dāng)從數(shù)據(jù)庫(kù)獲取數(shù)據(jù)時(shí)會(huì)打印,如果是從緩存中查詢并不會(huì)執(zhí)行到這里。
        log.info("從數(shù)據(jù)庫(kù)獲取產(chǎn)品: id = {}", id);
        Product product = new Product(id, "product", 100, "課本", 10);
        return Result.success(product);
    }

    /**
     * 更新產(chǎn)品信息
     * 通過(guò)@CacheEvict注解,當(dāng)更新產(chǎn)品時(shí),清除緩存中對(duì)應(yīng)產(chǎn)品的數(shù)據(jù),確保獲取到最新的數(shù)據(jù)
     * 設(shè)置allEntries為true,表示清除整個(gè)緩存中的所有產(chǎn)品數(shù)據(jù)
     *
     * @param product 產(chǎn)品對(duì)象,包含更新后的詳細(xì)信息
     * @return 返回更新結(jié)果,成功更新時(shí)返回成功標(biāo)志
     */
    @PutMapping("/updateProduct")
    @CacheEvict(value = "productsCache", key = "#product.id")
    public Result updateProduct(@RequestBody Product product) {
        // 更新操作
        return Result.success();
    }

    /**
     * 刪除指定ID的產(chǎn)品
     * 通過(guò)@CacheEvict注解,當(dāng)刪除產(chǎn)品時(shí),清除緩存中對(duì)應(yīng)產(chǎn)品的數(shù)據(jù)
     *
     * @param id 待刪除產(chǎn)品的ID
     * @return 返回刪除結(jié)果,成功刪除時(shí)返回成功標(biāo)志
     */
    @DeleteMapping("/deleteProductById")
    @CacheEvict(value = "productsCache", key = "#id")
    public Result deleteProductById(Long id) {
        // 刪除操作
        return Result.success();
    }


}

4.6 測(cè)試

4.6.1 查詢測(cè)試

因?yàn)槲覀冊(cè)诓樵兘涌谏鲜褂玫?code>@Cacheable接口,所以當(dāng)執(zhí)行查詢操作時(shí),第一次查詢會(huì)從數(shù)據(jù)庫(kù)中獲取,因此會(huì)輸出「從數(shù)據(jù)庫(kù)獲取產(chǎn)品: id = x」,此時(shí)查看Redis控制臺(tái)會(huì)發(fā)現(xiàn)出現(xiàn)一個(gè)對(duì)應(yīng)的緩存,之后的每次查詢都會(huì)從Redis中查詢(控制臺(tái)不會(huì)輸出「從數(shù)據(jù)庫(kù)獲取產(chǎn)品: id = x」),直到對(duì)應(yīng)的緩存數(shù)據(jù)時(shí)間結(jié)束。

發(fā)送查詢請(qǐng)求:

image-20240613203320506

查看Redis中的緩存數(shù)據(jù):

通過(guò)觀察可以發(fā)現(xiàn)CacheConfig類中的序列化配置起作用了,Redis中的數(shù)據(jù)不再是一堆亂碼,并且在右上角還有我們之前配置的緩存的過(guò)期時(shí)間(我們之前配置的300s)。

image-20240613203847598

查看控制臺(tái)發(fā)現(xiàn)本次查詢?yōu)閺臄?shù)據(jù)庫(kù)查詢:

image-20240613212356495

再次發(fā)送會(huì)發(fā)現(xiàn)數(shù)據(jù)成功的查詢了:

image-20240613203438434

再次查詢控制臺(tái)發(fā)現(xiàn)并沒(méi)有輸出從數(shù)據(jù)庫(kù)獲取產(chǎn)品: id = 1,說(shuō)明本次查詢?yōu)閺腞edis緩存中獲取數(shù)據(jù)。

4.6.2 更新、刪除測(cè)試

因?yàn)橹拔覀冊(cè)诟潞蛣h除接口上使用的@CacheEvict注解,所以當(dāng)執(zhí)行更新或者刪除操作時(shí),會(huì)將Redis中對(duì)應(yīng)的產(chǎn)品緩存數(shù)據(jù)刪除。

分別發(fā)送更新請(qǐng)求和刪除請(qǐng)求,然后再次查看Redis中的緩存數(shù)據(jù):

image-20240613215742944

image-20240613221930757

可以發(fā)現(xiàn)Redis當(dāng)中對(duì)應(yīng)的緩存數(shù)據(jù)被刪除了,符合我們的設(shè)計(jì):

image-20240613204329734

5. 總結(jié)

在本文中,我們?cè)敿?xì)介紹了如何在Spring Boot項(xiàng)目中使用Spring Cache和Redis實(shí)現(xiàn)數(shù)據(jù)緩存,并簡(jiǎn)單講解了使用Cache Aside Pattern來(lái)解決數(shù)據(jù)一致性問(wèn)題,希望對(duì)大家學(xué)習(xí)有所幫助。如有問(wèn)題,大家可以私信或者在評(píng)論區(qū)詢問(wèn)。

以上就是使用Spring Cache和Redis實(shí)現(xiàn)查詢數(shù)據(jù)緩存的詳細(xì)內(nèi)容,更多關(guān)于Spring Cache Redis查詢數(shù)據(jù)緩存的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論