SpringBoot使用Redis作为缓存器缓存数据的操作步骤以及避坑方案

1.非注解式实现

2.1使用之前要明确使用的业务场景

例如我们在登录时,可以让redis缓存验证码,又如在分类下显示菜品数据时,我们可以对分类和菜品进行缓存数据等等。

2.2导入Redis相关依赖

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

2.3在使用的controller层导入RedisTemplate

例如:

说明一下:这里为什么使用@Resource注解而不使用@Autowired注解。

在Spring框架中,@Resource和@Autowired都是用来完成依赖注入的注解,它们可以将其他组件或者资源注入到当前的类中。在Spring框架中,@Resource和@Autowired都是用来完成依赖注入的注解,它们可以将其他组件或者资源注入到当前的类中

@Resource是Java提供的一个通用注解,而@Autowired是Spring框架提供的注解。@Resource注解默认按照名称进行装配,通过name属性指定注入的目标对象名称。而@Autowired默认按照类型进行装配,它会自动根据类型选择合适的对象进行注入。另外,@Autowired注解可以配合@Qualifier注解一起使用,通过指定具体的bean名称来完成注入。

其次,@Resource可以用于注入任意的bean,包括其他类、接口、甚至是字符串等类型的资源而@Autowired注解主要用于注入其他的bean对象

此外,@Resource注解可以标注在字段、setter方法、构造方法和方法上,而@Autowired注解通常标注在字段和构造方法上。

在实践中,选择使用@Resource还是@Autowired取决于具体的需求和场景。如果需要按照名称进行注入,或者需要注入的对象是一个非Spring托管的对象,可以使用@Resource注解。如果只是简单的注入Spring托管的对象,并且希望按照类型自动选择合适的bean进行注入,可以使用@Autowired注解。

需要注意的是,@Resource和@Autowired注解都需要对应的类进行配置,以让Spring框架知道需要进行依赖注入的对象。

通过上面的说明,其实我们自己内心里已经有答案,孰强孰弱啦。

 2.4此时,我们要配置Redis

2.4.1配置application.yml

2.4.2编写RedisConfig配置类

由于Redis是一个内存数据库,它将数据存储在内存中,因此需要将数据序列化为字节流进行存储。在将数据存入Redis或从Redis中取出数据时,需要进行序列化和反序列化的操作。

@Configuration
public class RedisConfig extends CachingConfigurerSupport {


    /**
     * 自定义RedisTemplate
     * 设置Redis序列化方式,默认使用的是JDKSerializer的序列化方式,效率低,所以这里设置使用FastJsonRedisSerializer
     */
    @Bean
    @SuppressWarnings(value = {"unchecked", "rawtypes"})
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        // 设置redis连接(LettuceConnectionFactory实现了RedisConnectionFactory)
        redisTemplate.setConnectionFactory(connectionFactory);

        FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);

        // key设置StringRedisSerializer序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // Hash key设置序列化
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());


        return redisTemplate;
    }

}

可以参考一下,或许有更好的,大家可以借鉴一下。

2.5使用缓存(验证码为例)

 此时我们可以测试一下,在此之前呢,怎么看缓存数据是一个问题,所以,安排一下Redis的可视化工具:

链接:https://pan.baidu.com/s/1OUNza9ea9fQepXqNTeTq-g 
提取码:frpd

2.6测试

 

这只是一个简单的应用,然后我们再来一个其他的案例:缓存菜品数据

业务场景如下:

每个分类,比如湘菜,川菜,每次点击都需要再次重新查询数据库,不仅压力更大而且造成资源浪费,我们可以把这些查询的数据,按菜品分类给存入redis中,设置其30分钟生存周期,这样再次点击查看,就不会再查询数据库,直接从redis中获取数据,降低服务器压力也避免资源浪费。

缓存逻辑:

我们先动态构造唯一key值,然后根据key来获取value,接下来判断value是否为空,若不为空则表示redis中有该分类下的数据,直接返回;若为空则需要去数据库查询数据,然后再把查询的数据放入redis缓存中,下次再查询直接走redis缓存,不用再次查询数据库。

这个就不再演示了,到这里我们就可以明显觉得,代码量上来了,这只是一个查询都这样,再细想一下,这个查询会不会因为这个缓存出现问题,比如说我们新增了菜品,修改了菜品,删除了菜品,这个缓存区是不是得动一动,那这个重复的代码多不多,显而易见。

2.使用Spring Cache框架优化Redis缓存的过程

简单介绍一下这一位大咖:Spring Cache框架是Spring框架提供的一套基于注解的缓存解决方案,它在应用程序中简化了缓存操作的管理和使用。

Spring Cache框架的核心思想是通过在方法上添加缓存注解,来实现自动缓存的功能。它提供了一些常用的注解,如:

  • @Cacheable:标注在方法上,表示该方法的返回结果可以被缓存,当方法被调用时,会首先检查缓存,如果缓存命中,则直接返回缓存中的结果,不再执行方法体中的逻辑。
  • @CachePut:标注在方法上,表示该方法的返回结果需要更新缓存,每次方法被调用后,都会将返回结果更新到缓存中。
  • @CacheEvict:标注在方法上,表示该方法会清除缓存中的数据,可以用于在更新或删除数据时清除相应的缓存。

2.1导入Spring Cache依赖

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

2.2启动类上加上注解开启缓存

 2.3返回结果类实现序列化接口

 2.4改造上一个案例的代码

不用意外,就是什么关于redis的什么都不剩了 ,我们只需要再控制层的接口上加上一个注解,就完事了。

 2.5测试

测试后即会在redis中产生一个这样的目录结构

对照接口上的注解再理解一下你就会明白其中的意思了。

这个时候你和非注解方式对比你会发现一个问题,过期时间去哪啦,没法设置过期时间了!

3.再次优化Spring Cache使用 

使用@Cacheable时,无法直接设置过期时间,需要自定义RedisCacheManager来实现ttl设置。

3.1编写TtlRedisCacheManager类来获取注解@Cacheable的参数

public class TtlRedisCacheManager extends RedisCacheManager {
    public TtlRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
        super(cacheWriter, defaultCacheConfiguration);
    }

    @Override
    protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
        String[] cells = StringUtils.delimitedListToStringArray(name, "=");
        name = cells[0];
        if (cells.length > 1) {
            long ttl = Long.parseLong(cells[1]);
            // 根据传参设置缓存失效时间,默认单位是秒
            cacheConfig = cacheConfig.entryTtl(Duration.ofMinutes(ttl));
        }
        return super.createRedisCache(name, cacheConfig);
    }
}

3.2修改RedisConfig配置类

@Configuration
public class RedisConfig extends CachingConfigurerSupport {


    /**
     * 自定义RedisTemplate
     * 设置Redis序列化方式,默认使用的是JDKSerializer的序列化方式,效率低,所以这里设置使用FastJsonRedisSerializer
     */
    @Bean
    @SuppressWarnings(value = {"unchecked", "rawtypes"})
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        // 设置redis连接(LettuceConnectionFactory实现了RedisConnectionFactory)
        redisTemplate.setConnectionFactory(connectionFactory);

        FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);

        // key设置StringRedisSerializer序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // Hash key设置序列化
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());


        return redisTemplate;
    }

    /**
     * 实例化自定义的缓存管理器
     */
    @Bean
    @Primary
    @SuppressWarnings(value = {"unchecked", "rawtypes"})
    public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(Objects.requireNonNull(redisTemplate.getConnectionFactory()));
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
        return new TtlRedisCacheManager(redisCacheWriter, redisCacheConfiguration);
    }


}

注意:项目中已配置了RedisCacheManager需要在原配置的bean上添加注解@Primary,以免造成干扰

3.3修改controller层数据接口的注解

根据你在RedisCacheManager中设置的什么格式来填写value即可。

即完成对Redis缓存数据的使用。有什么问题还请留言。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3 前端编码规范

prettier 配置 1. vscode 安装prettier 的 插件 2. 新建 .prettierrc 文件 {"semi": false, // 不尾随分号"singleQuote": true, // 使用单引号"trailingComma": "none" // 多行逗号分隔的语法&#xff0c;最后一行不加逗号 }eslin…

数据库应用:MySQL备份与恢复

目录 一、理论 1.数据备份 2.完全备份与恢复 3.完全备份与恢复应用 4.增量备份与恢复 5.增量备份与恢复应用 6.使用脚本备份 7.日志管理 二、实验 1.完全备份与恢复 2.增量备份与恢复 3.使用脚本备份 三、问题 1.mysqldump报错 四、总结 一、理论 1.数据备份 …

HDFS与MapResource笔记

客户端向NN请求上传文件 NN回应可以上传 请求上传块,返回DN 所以后面就比较慢 找最近的服务器进行 64K发到1节点,1节点立刻发给2节点,同时1节点自动开始落盘,这里,3个节点是同时落盘的. 因为缓存是在内存中,而持久化是将数据存到磁盘上. 副本节点选择: 1.安全:放不同机架 2.速…

销售易的12年与七个瞬间

导读&#xff1a;企业级没有捷径 12年对一家企业意味着什么&#xff1f; 在消费互联网领域&#xff0c;12年足够长&#xff0c;短短几年内上市的故事过去屡见不鲜。在企业服务的toB领域&#xff0c;产业成熟和企业发展的时间维度被拉长&#xff0c;但故事同样精彩。 2023年7月1…

flask实现get和post请求

1、实现get请求 在项目根目录创建app.py 代码如下&#xff1a; from flask import Flask,render_template,requestapp Flask(__name__)app.route("/regist/user/", methods[GET]) def regist():return render_template("regist.html") #默认去templat…

招聘小程序制作:连接人才与企业

随着人才市场的竞争日益激烈&#xff0c;招聘小程序成为了企业寻找优秀人才和求职者找到理想工作的重要工具。通过招聘小程序&#xff0c;企业可以发布招聘信息、筛选简历&#xff0c;而求职者可以浏览职位、提交简历等。 招聘小程序的好处 精准匹配人才&#xff1a;招聘小程序…

Java二叉树

目录 一、树形结构 1.1 概念 1.2 树的性质 1.3 树的表示形式 二、二叉树 2.1 概念 2.2 两种特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储 2.5 二叉树的基本操作 2.5.1 二叉树的遍历 2.5.2 二叉树的基本操作 一、树形结构 1.1 概念 树是一种非线性的数据结构&#xff0…

Linux搭建node环境-MobaXterm+node+pm2安装

1.登录session 2.安装X11-forwarding 我也不知道这个有什么用&#xff0c;但是有个叉叉在那里有点难受&#xff0c;就把它解决了什么是X11-forwarding&#xff1f;怎么使用&#xff1f; yum install xorg-x11-xauth xorg-x11-fonts-* xorg-x11-font-utils xorg-x11-fonts-Ty…

如何将jar 包下载到自定义maven仓库

下载命令 mvn install:install-file -Dfileartifactid-version.jar -DgroupIdgroupid -DartifactIdartifactid -Dversionversion -Dpackagingjar -DlocalRepositoryPath. -DcreateChecksumtrue参数解释 在上述命令中&#xff0c;需要替换以下参数&#xff1a; artifactid-vers…

SQL中为何时常见到 where 1=1?

你是否曾在 SELECT 查询中看到过 WHERE 11 条件。我在许多不同的查询和许多 SQL 引擎中都有看过。这条件显然意味着 WHERE TRUE&#xff0c;所以它只是返回与没有 WHERE 子句时相同的查询结果。此外&#xff0c;由于查询优化器几乎肯定会删除它&#xff0c;因此对查询执行时间没…

cocosCreator 3.6以上接入腾迅Bugly 捕捉JS错误 Android

cocosCreator3.6以上接入Bugly上报其实很简单&#xff0c;不需要网上那么多弯弯绕&#xff0c;三须三步走。 1. 按照官网方式接入android的bugly 2. android端写一个Bugly上报管理类 3. 修改你工程目录下native\engine\common\Classes\目录下的Game.h, Game.cpp两个文件&…

基于python的爬虫实现

定义 爬虫&#xff08;Web crawler&#xff09;&#xff0c;也被称为网络爬虫、网络蜘蛛或网络机器人&#xff0c;是一种自动化程序&#xff0c;用于浏览互联网并收集网页内容。 基本原理 爬虫的工作原理是通过发送HTTP请求从网页服务器获取网页的内容&#xff0c;然后解析网…

计算机专升本基础笔记二 进制转换及二进制运算规则

进制转换及二进制运算规则 什么是进制&#xff1f;     进制就是进位计数制&#xff0c;是人为定义的带进位的计数方法。我们的时间就是六十进制(满60秒进一分钟&#xff0c;满60分钟进1小时&#xff09;&#xff1b;对于任何一种进制—X进制&#xff0c;就表示每一位上的数…

GUI-Menu菜单实例(颜色+线型菜单)

运行代码&#xff1a; //GUI-Menu菜单实例&#xff08;颜色线型菜单&#xff09; #include"std_lib_facilities.h" #include"GUI/Simple_window.h" #include"GUI/GUI.h" #include"GUI/Graph.h" #include"GUI/Point.h"struc…

Java的数据结构-Map集合

文章目录 Map概述Map常用方法Map遍历元素的方法1.方法一&#xff1a;keySet()2.方法二&#xff1a;entrySet() HashMap Map概述 1、Map和collection没有继承关系2、Map集合以key和value的方式存储数据&#xff1a;键值对key和value都是引用数据类型。key和value都是存储对象的…

【LocalSend】开源跨平台的局域网文件传输工具,支持IOS、Android、Mac、Windows、Linux

工作前提条件&#xff1a;设备使用相同的局域网。 LocalSend is a cross-platform app that enables secure communication between devices using a REST API and HTTPS encryption. Unlike other messaging apps that rely on external servers, LocalSend doesn’t require …

【网络安全】渗透测试工具——Burp Suite

渗透测试工具Burp Suite主要功能详解 前言一、 Proxy模块1.1 界面布局1.1.1 菜单栏&#xff08;1&#xff09; 菜单栏 Burp&#xff08;2&#xff09; 菜单栏 project&#xff08;3&#xff09; 菜单栏 Intruder&#xff08;4&#xff09; 菜单栏 Repeater&#xff08;5&#x…

C# Modbus通信从入门到精通(2)——Modbus RTU协议原理

Modbus RTU是串行链路上的协议,也就是说Modbus RTU是通过串口通信来实现的,它可以通过RS232、RS485物理层的接口来实现,同时它也是一个主从协议,在同一时间总线上只能有一个主站和一个或多个(最多247)个从站。Modbus通信总是由主站发起,从站没有接收到主站的请求时不会发…

Kubernetes轻量级日志工具Loki安装及踩坑记录

Loki简介 Loki是Grafana出品的一个轻量级日志系统&#xff0c;熟悉ELK的都知道ELK使用起来的成本&#xff0c;而且仅仅是日志检索使用ELK的话有点大材小用了。Loki8技术栈中使用了以下组件。 Promtail 用来将容器日志发送到 Loki 或者 Grafana 服务上的日志收集工具&#xff0c…

基于单片机的智能鞋柜的设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;通过DHT11温湿度采集&#xff1b;通过按键设置逻辑处理&#xff1b;通过LED紫外线消毒&#xff1b;通过继电器控制风扇进行换气除湿&#xff1b;通过继电器控制加热片进行加热&#xff1b;整个电路以5v供电; 电路图 PCB 源代码 #i…