重学SpringBoot3-集成Redis(二)之注解驱动

news2024/10/8 15:41:49

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》
期待您的点赞👍收藏⭐评论✍

重学SpringBoot3-集成Redis(二)之注解驱动

  • 1. 为什么选择 Redis 作为缓存?
  • 2. 如何在 Spring Boot 中启用 Redis 缓存?
    • 2.1 添加 Redis 依赖
    • 2.2 配置 Redis 连接
    • 2.3 启用缓存支持
  • 3. 注解驱动的缓存机制
    • 3.1 @Cacheable示例
    • 3.2 @CachePut示例
    • 3.3 @CacheEvict示例
  • 4. 自定义缓存管理
    • 4.1 RedisCacheConfiguration 类
      • 4.1.1. 过期时间(TTL - Time To Live)
      • 4.1.2. 键序列化方式
      • 4.1.3. 值序列化方式
      • 4.1.4. 禁用缓存空值(Disable Caching Null Values)
      • 4.1.5. 使用前缀(Use Cache Key Prefixes)
      • 4.1.6. 设置空闲时间(Idle Time)
      • 4.1.7. 组合多种配置
      • 4.1.8. 设置自定义的过期策略
    • 4.2 自定义缓存配置
  • 5. Redis 缓存的常见问题和优化建议
  • 6. 总结

Spring Boot 提供了对缓存的简便支持,使得开发者能够通过简单的注解实现缓存操作,减少重复代码的编写。本文将详细介绍如何在 Spring Boot 3 中使用 Redis 作为缓存,并通过注解驱动的方式进行缓存操作。

1. 为什么选择 Redis 作为缓存?

Redis 是一个高效的键值对存储系统,特别适合于构建高性能、可扩展的缓存层。其优点包括:

  • 高吞吐量:Redis 使用内存作为存储介质,读取和写入性能极快,能够支撑高并发的访问需求。
  • 数据持久化:尽管 Redis 是内存数据库,它也支持将数据持久化到磁盘,防止数据丢失。
  • 丰富的数据结构:Redis 不仅支持简单的字符串存储,还支持哈希、列表、集合等丰富的数据结构,适用于多种应用场景。
  • 易于扩展:通过 Redis 的集群功能,可以很容易地扩展 Redis 实例,处理更大规模的数据和请求。

2. 如何在 Spring Boot 中启用 Redis 缓存?

Spring Boot 提供了对缓存的开箱即用支持,开发者只需简单配置即可使用。具体参考上一章 重学SpringBoot3-集成Redis(一)。

2.1 添加 Redis 依赖

pom.xml 中引入 Redis 和 Spring Cache 相关依赖:

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

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

2.2 配置 Redis 连接

application.yml 中,配置 Redis 服务器地址及相关连接池配置:

spring:
  cache:
    type: redis     	 	# 使用 Redis 作为缓存类型
  data:
    redis:
      host: localhost
      port: 6379            # Redis 端口
      password: 			# 如果有密码可以在这里配置
      lettuce:
        pool:
          max-active: 100    # 最大并发连接数
          max-idle: 50       # 最大空闲连接数
          min-idle: 10       # 最小空闲连接数

2.3 启用缓存支持

在 Spring Boot 项目中,使用 @Cacheable 注解前,需要通过 @EnableCaching 注解启用缓存功能。可以在主应用类或者任何配置类中加上这个注解:

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableCaching
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

3. 注解驱动的缓存机制

Spring 提供了一组注解用于操作缓存,这些注解可以直接应用于方法上,使得代码更简洁。常用注解包括:

  • @Cacheable:用于标记一个方法的返回值是可缓存的。下一次调用该方法时,Spring 会直接从缓存中返回结果,而不是再次执行方法。
  • @CachePut:在方法执行后将返回值放入缓存。它与 @Cacheable 的区别在于,@CachePut 不会跳过方法执行,而是始终执行方法并更新缓存。
  • @CacheEvict:用于清除缓存中的某些条目,可以指定缓存的 key 或清空整个缓存空间。

3.1 @Cacheable示例

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    // 当方法第一次调用时,结果将被缓存起来,之后相同参数的调用将直接从缓存中获取数据
    @Cacheable(value = "user", key = "#p0")
    public User getUserById(Long id) {
        // 模拟数据库查询操作
        System.out.println("Fetching user with id: " + id);
        return new User(id, "User" + id);
    }
}

解释:

  • @Cacheable 用于缓存方法的返回值。
  • value = "user" 指定了缓存的名称,即 “user”。
  • key = "#p0" 指定了缓存的键值。这里的 #p0 是一个 SpEL 表达式,表示方法的第一个参数。

在这个例子中,方法 getUserById 第一次被调用时,结果会缓存到 Redis 中,并与 user::id 作为 key 存储。后续相同 id 的请求将直接从缓存返回,而无需执行方法。

@Cacheable添加缓存

3.2 @CachePut示例

有时候,我们希望方法执行后,不仅返回结果,还更新缓存,这时可以使用 @CachePut 注解。

import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    // 无论缓存中是否存在数据,该方法都会被执行,并且返回值会更新缓存
    @CachePut(value = "user", key = "#p0.id")
    public User updateUser(User user) {
        System.out.println("Updating user with id: " + user.getId());
        // 模拟数据库更新操作
        user.setName("Updated " + user.getName());
        return user;
    }
}

解释:

  • @CachePut 用于更新缓存中的值。
  • value = "user" 指定了缓存的名称,即 “user”。
  • key = "#p0.id" 指定了缓存的键值。这里的 #p0 是一个 SpEL 表达式,表示方法的第一个参数,即 User 对象。.id 表示取 User 对象的 id 属性作为缓存键。

连续两次调用 curl "http://localhost:8080/api/redis/updAndSave?id=2" ,可以从日志中看到,每次方法都执行了,并且 user 对象加入到了缓存中。

@CachePut更新缓存

3.3 @CacheEvict示例

为了保持缓存数据的准确性,某些情况下需要手动清除缓存中的数据。@CacheEvict 注解允许我们在数据修改或删除时,移除缓存中的旧数据。

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    // 清除缓存中的指定用户数据
    @CacheEvict(value = "user", key = "#p0")
    public void deleteUser(Long id) {
        System.out.println("Deleting user with id: " + id);
        // 模拟数据库删除操作
    }

    // 清空整个缓存空间
    @CacheEvict(value = "user", allEntries = true)
    public void clearCache() {
        System.out.println("Clearing all user cache");
    }
}

调用 curl "http://localhost:8080/api/redis/delUser?id=1" ,删除 key 为 user::1 的缓存。

@CacheEvict删除缓存

调用 curl "http://localhost:8080/api/redis/delAllUser" ,删除所有前缀为 user:: 的缓存。

@CacheEvict删除所有缓存

4. 自定义缓存管理

以上缓存名称、过期时间和序列化方式都是默认设置,Spring 允许我们自定义缓存管理器。在大多数情况下,默认配置足够使用,但如果需要定制化的缓存行为,我们可以自定义缓存配置。通过实现 RedisCacheConfiguration,我们可以设置缓存的过期时间、序列化方式等。

4.1 RedisCacheConfiguration 类

Spring Boot 3 中,RedisCacheConfiguration 类是用于配置 Redis 缓存行为的核心组件之一。它提供了多种方法,用于自定义 Redis 缓存的各类设置,比如缓存过期时间、序列化策略等。以下是一些常用的配置选项:

4.1.1. 过期时间(TTL - Time To Live)

设置缓存条目的默认生存时间(TTL)。这决定了缓存数据在 Redis 中保留的时间。

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
    .entryTtl(Duration.ofMinutes(10)); // 设置缓存10分钟后过期

4.1.2. 键序列化方式

默认情况下,Redis 使用二进制存储键和值。RedisCacheConfiguration 提供了设置键(key)序列化方式的方法。常见的序列化方式包括 StringRedisSerializer,可以使用它来确保键以字符串格式存储:

import org.springframework.data.redis.serializer.StringRedisSerializer;

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
    .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));

4.1.3. 值序列化方式

同样,值(value)的序列化方式也可以自定义。常用的序列化方式有 GenericJackson2JsonRedisSerializer,它将对象序列化为 JSON 格式:

import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
    .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

4.1.4. 禁用缓存空值(Disable Caching Null Values)

你可以配置不缓存空值,避免 Redis 存储 null,减少缓存的无效占用。

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
    .disableCachingNullValues();

4.1.5. 使用前缀(Use Cache Key Prefixes)

Redis 中默认会为缓存键值加上一个命名空间的前缀,以防止不同缓存键冲突。可以自定义这个前缀,也可以关闭它:

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
    .prefixCacheNameWith("myApp::")  // 自定义缓存键前缀
    .computePrefixWith(cacheName -> "customPrefix::" + cacheName + "::");  // 使用自定义逻辑

要禁用前缀:

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
    .disableKeyPrefix();

4.1.6. 设置空闲时间(Idle Time)

你可以设置一个键的空闲时间,Redis 将会在指定的时间内删除不再被访问的键。

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
    .entryTtl(Duration.ofMinutes(10))
    .enableTimeToIdle();

4.1.7. 组合多种配置

可以将多个配置组合到一起:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@Configuration
public class CacheConfig {

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration() {
        return RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(10))  // 缓存的过期时间
            .disableCachingNullValues()        // 不缓存 null 值
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))  // 自定义 key 序列化
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); // 自定义 value 序列化
    }
}

4.1.8. 设置自定义的过期策略

可以为不同的缓存区域设置不同的过期策略。例如:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;

@Configuration
public class CacheConfig {

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5));
        RedisCacheConfiguration longLivedConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));
        
        Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
        cacheConfigurations.put("shortLivedCache", defaultConfig);
        cacheConfigurations.put("longLivedCache", longLivedConfig);
        
        return RedisCacheManager.builder(connectionFactory)
            .withInitialCacheConfigurations(cacheConfigurations)
            .build();
    }
}

4.2 自定义缓存配置

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@Configuration
public class CacheConfig {

    @Bean
    public RedisCacheConfiguration cacheConfiguration() {
        return RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(10))  // 设置缓存过期时间为 10 分钟
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // 自定义 Key 序列化器
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); // 自定义 Value 序列化器
    }
}

通过这种方式,我们可以对缓存的过期时间、序列化方式进行更细粒度的控制。

自定义配置

5. Redis 缓存的常见问题和优化建议

尽管 Redis 是一个高效的缓存解决方案,但在实际应用中,仍然有一些需要注意的问题:

  • 缓存穿透:大量请求查询缓存中不存在的 key,导致所有请求都直接打到数据库上,降低系统性能。解决方案是使用布隆过滤器来拦截非法请求。
  • 缓存雪崩:当大量缓存同时过期时,可能会导致瞬间的大量请求直接涌入数据库,造成系统崩溃。可以通过设置不同的过期时间(TTL)来缓解这一问题。
  • 缓存击穿:某个热点 key 在缓存过期后,大量并发请求直接打到数据库上。解决方案是使用互斥锁,避免大量请求同时加载缓存。

6. 总结

通过本文,我们学习了如何在 Spring Boot 3Java 17 中使用 Redis 作为缓存。Spring 提供了注解驱动的缓存操作方式,使得缓存操作变得非常简单易用。通过合理配置和使用缓存,我们能够极大地提升系统的性能和响应速度。在生产环境中,合理的缓存策略、过期时间和缓存层优化将会进一步提高系统的稳定性和扩展能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2196679.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多模态大模型调研BLIP、BLIP2、InstructBLIP

ITC:图像向量与文本向量对齐在同一特征空间 ITM:二分类任务。负样本构建:前方ITC分错的地方&#xff0c;在对比学习的基础上&#xff0c;更细粒度的对其特征。 LM:GPT的生成任务&#xff0c;将文本重新进行预测。 BLIP另一个贡献在于弱监督图文数据清洗方面&#xff0c;通过训…

学习threejs,模拟窗户光源

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言二、&#x1f340;绘制任意字体模型…

棒球运动物体检测系统源码分享

棒球运动物体检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

应用界面编写(十四)

一. 介绍QT 接下来我们会在Qt Creater来进行界面的编写&#xff0c;并且在荔枝派中运行。那么我们有必要了解一下Qt到底是什么呢&#xff1f;它又为什么可以在荔枝派中运行呢&#xff1f; QT是一个跨平台的应用程序和用户界面框架&#xff0c;用于开发具有图形界面的软件。而…

【最新版】Stable Diffusion4.9(AI绘画)下载及安装教程(附软件安装包)!

随着技术的迭代&#xff0c;目前 Stable Diffusion 已经能够生成非常艺术化的图片了&#xff0c;完全有赶超人类的架势&#xff0c;已经有不少工作被这类服务替代&#xff0c;比如制作一个 logo 图片&#xff0c;画一张虚拟老婆照片&#xff0c;画质堪比相机。 最新 Stable Di…

日常物品实例分割系统源码&数据集分享

日常物品实例分割系统源码&#xff06;数据集分享 [yolov8-seg-dyhead-DCNV3&#xff06;yolov8-seg-SPPF-LSKA等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Globa…

Maven - 依赖管理

依赖配置 在pom.xml的project标签内添加dependencies标签&#xff0c;之后添加依赖配置。 <dependencies><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.4.5</version>…

Acwing 记忆化搜索

Acwing 901.滑雪 输入样例&#xff1a; 5 5 1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9 输出样例&#xff1a; 25 实现思路&#xff1a; 状态表示f[i][j]&#xff0c;表示从点(i,j)出发的最长路径长度集合划分可分为四种情况&#xff1a;从点(i,j)出…

Mybatis框架梳理——更新中

Mybatis框架梳理 前言1.ORM2.模块划分2.1 ORM的实现2.2 SQL的映射2.3 插件机制2.4 缓存机制2.5 其他2.5.1 用到的设计模式 3. 愿景 前言 如果让我聊一聊mybatis&#xff0c;我该怎么说呢&#xff1f;开发中时时刻刻都在用它&#xff0c;此时此刻&#xff0c;脑海中却只浮现ORM框…

揭秘:ARM 工业计算机缘何替代树莓派

工业自动化、物联网以及嵌入式系统等领域对高性能、稳定可靠的计算设备的需求日益增长。国产 ARMxy工业计算机的出现&#xff0c;为这些领域带来了新的机遇和选择。特别是那些采用国产芯片如全志、瑞芯微等&#xff0c;并支持 Ubuntu 系统的工业计算机&#xff0c;展现出了令人…

微信公众号菜单栏----第⑦篇

如果你是新手小白&#xff0c;请从微信公众号开发第一篇看起&#xff1a;微信公众号开发-接口配置信息&#xff08;第①篇&#xff09;_微信公众号 接口配置信息怎么设置-CSDN博客 代码&#xff1a; <?php// 获取菜单配置数据$menuConfig array(button > array(array(…

认知战认知作战:激发认知战战术分享热情的秘诀

认知战认知作战&#xff1a;激发认知战战术分享热情的秘诀 认知战认知作战&#xff1a;激发认知战战术分享热情的秘诀 关键词&#xff1a;认知战, 认知作战, 创造独特体验, 融入社交元素, 情感共鸣策略, 分享激励机制, 战略形象塑造, 个性化内容推荐,认知作战,新质生产力,人类…

Observability:使用 OpenTelemetry 自动检测 Go 应用程序

作者&#xff1a;来自 Elastic Damien Mathieu 使用 OpenTelemetry 检测 Go 应用程序可以深入了解应用程序的性能、依赖项和错误。我们将向你展示如何使用 Docker 自动检测 Go 应用程序&#xff0c;而无需更改应用程序代码。 在快节奏的软件开发领域&#xff0c;尤其是在云原生…

网络资源模板--Android Studio 通讯录App

目录 一、项目演示 二、项目测试环境 三、项目详情​编辑 四、完整的项目源码 一、项目演示 网络资源模板--通讯录App 二、项目测试环境 三、项目详情 首页 package com.example.addressbook.activity;import androidx.appcompat.app.AppCompatActivity; import androidx.c…

Qwen变体新成员加一,英伟达训练 NVLM-D-72B 视觉大模型

今天&#xff08;2024 年 9 月 17 日&#xff09;&#xff0c;我们推出了前沿级多模态大语言模型&#xff08;LLM&#xff09;系列 NVLM 1.0&#xff0c;它在视觉语言任务上取得了最先进的结果&#xff0c;可与领先的专有模型&#xff08;如 GPT-4o&#xff09;和开放存取模型&…

2024高校网络安全管理运维赛 wp

0x00 前言 本文是关于“2024高校网络安全管理运维赛”的详细题解&#xff0c;主要针对Web、Pwn、Re、Misc以及Algorithm等多方向题目的解题过程&#xff0c;包含但不限于钓鱼邮件识别、流量分析、SQLite文件解析、ssrf、xxe等等。如有错误&#xff0c;欢迎指正。 0x01 Misc 签到…

纯干货!一个白帽子挖漏洞经验细致分享_白帽子找漏洞一天能多少

不知道是不是很多人和我一样&#xff0c;每天刷着漏洞&#xff0c;看着自己的排名一位一位的往上提升&#xff0c;但是&#xff0c;但是。总感觉怪怪的&#xff0c;为什么别人刷的漏洞都是现金&#xff0c;而自己刷的漏洞都是给库币。别人一天为什么提交那么多漏洞&#xff0c;…

winform appconfig

文章目录 添加一个appconfig配置文件的结构读取写入 这是wiform自带的配置文件&#xff0c;格式为xml 其位置在程序根目录下 添加一个appconfig 首先默认情况下&#xff0c;winform会自动创建一个名叫appconfig的配置文件&#xff0c;位于程序根目录下 如果需要手动创建更多…

【路径规划】基于球面向量的粒子群优化算法(SPSO)

摘要 本文提出了一种基于球面向量的粒子群优化算法&#xff08;Spherical Vector-based Particle Swarm Optimization, SPSO&#xff09;用于解决路径规划问题。该算法通过球面坐标系表示粒子的位置更新&#xff0c;增强了搜索空间的探索能力和全局优化性能。通过与遗传算法&a…