SpringBoot学习笔记【part14】Spring Cache + Redis 集成缓存数据

news2024/11/15 18:25:49

Spring Cache 是一个非常优秀的缓存组件,方便切换各种底层Cache(如:redis)
使用Spring Cache的好处:

  1. 提供基本的Cache抽象,方便切换各种底层Cache;
  2. 通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成;
  3. 提供事务回滚时也自动回滚缓存;
  4. 支持比较复杂的缓存逻辑。

项目集成Spring Cache + Redis,步骤如下。

第一步,添加依赖

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

<!-- spring2.X集成redis所需common-pool2-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.6.0</version>
</dependency>

第二步,配置application.properties

spring.redis.host=192.168.3.100
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000

spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0

第三步,添加配置类

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;  
import java.time.Duration;


@Configuration
@EnableCaching
public class RedisConfig {

    /**
     * 1.自定义key规则(自定义key为类名拼接方法名拼接参数名)
     * @return
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }

    /**
     * 2.设置RedisTemplate规则
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        //序列号key value
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * 3.设置CacheManager缓存规则
     * @param factory
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

@EnableCaching 注解用于开启缓存,并配置Redis缓存管理器。@EnableCaching 将触发后置处理器,,检查每一个 Spring bean 的 public 方法是否存在缓存注解。如果找到方法有缓存注解,则自动创建一个代理拦截方法调用和处理相应的缓存行为。

第四步,使用Spring Cache

常用缓存标签注解

@Cacheable (查)

根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。

参数说明
value缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames与 value 差不多,二选一即可
key可选属性,可以使用 SpEL 标签自定义缓存的key
keyGenerator指定自定义key规则生成器

@CachePut (增)

使用该注解标志的方法,每次执行时会将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。

参数说明
value缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames与 value 差不多,二选一即可
key可选属性,可以使用 SpEL 标签自定义缓存的key
keyGenerator指定自定义key规则生成器

@CacheEvict (删、改)

使用该注解标志的方法,会清空指定的缓存,让下次查操作时再自动更新最新的缓存。一般用在更新或者删除方法上。

参数说明
value缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames与 value 差不多,二选一即可
key可选属性,可以使用 SpEL 标签自定义缓存的 key
allEntries是否清空所有缓存,默认为 false。如果指定为 true,则方法调用后将立即清空所有的缓存
beforeInvocation是否在方法执行前就清空,默认为 false。如果指定为 true,则在方法执行前就会清空缓存

第五步,编码并测试

注:在后端架构中,缓存的处理应该放在 Service 层,也就是以上 3 个注解应该标记在 Service 方法上。

启动服务器测试,成功写入 redis。

在这里插入图片描述

记录
        在测试过程中碰到一个问题,启动 Spring Cache 后,查询方法将不执行了。经过排查发现后台报错 Unable to connect to 192.168.3.100:6379 ,这个错误时因为redis 默认端口号 6379 在Linux防火墙中不允许进行远程连接。
        需要执行如下Linux命令 /sbin/iptables -I INPUT -p tcp --dport 6379 -j ACCEPT 在防火墙中开启 6379 端口的远程服务。

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

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

相关文章

基于MMdet的Cascade MASKRCNN 原理及源码解读

目录 一、原理 二、源码解读 1、总参数文件configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco.py 2、模型配置字典../_base_/models/cascade_mask_rcnn_r50_fpn.py 3、基于检测器类搭建模型 CascadeRCNN 4、backbone&#xff08;ResNet&#xff09; 5、neck&am…

深度学习数据标注_Lableme

图像标注工具Lable labelme 是一款图像标注工具&#xff0c;主要用于神经网络构建前的数据集准备工作&#xff0c;因为是用 Python 写的&#xff0c;所以使用前需要先安装 Python 集成环境 anaconda。 anaconda 安装 anaconda下载地址如下&#xff1a; https://www.anaconda…

数据结构:循环链表、双向链表和有序表

1、循环链表 循环链表(circular linked list)是线性表的另一种形式的链式存储表示。它的特点是表中最后一个结点的指针域指向第一个结点,整个链表成为一个由链指针相链接的环。对于循环链表,通常还在表中第一个结点之前“附加”一个“头结点”,并令“头指针”指向最后一个结点…

【算法基础】基础算法之排序

&#x1f63d;PREFACE&#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐ 评论&#x1f4dd;&#x1f4e2;系列专栏&#xff1a;https://blog.csdn.net/weixin_59954106/category_12108349.html&#x1f4aa;种一棵树最好是十年前其次是现在目录 1.快排 步骤 思路方法 题目…

ABB机器人仿真软件robotstudio v6.08安装教程

ABB机器人仿真软件robotstudio v6.08安装教程 具体步骤可参考以下内容: 注意:安装之前,最好将电脑的名称改为英文,否则可能会安装不成功, 第1步:将下载的安装包解压缩, 第2步:找到解压后的文件中的RobotStudio6.08, 第3步:找到“setup.exe”, 第4步:软件正在…

Open3D 深度图像转点云数据(Python版本)

文章目录 一、简介二、代码实现三、实现效果测试数据参考文献一、简介 深度图像的获取有很多方式,如激光雷达、结构光以及深度相机等,网上很多教程都是在讲解通过深度相机所获取的深度图像转换为三维点云数据(相机内参、外参),但是通过激光雷达所生成的深度相机通常与相机…

数据分析-决策树

我们生活中遇到很多问题其实把他们抽象成一个数学模型&#xff0c;都可以抽象为一个决策树。&#xff08;比如打篮球&#xff09; 我们总是会经历两个阶段&#xff1a;构造、剪枝 构造 什么是构造呢&#xff1f;构造就是生成一棵完整的决策树。简单来说&#xff0c;构造的过程…

【MySQL基础】MySQL多表操作详解

序号系列文章4【MySQL基础】MySQL表的七大约束5【MySQL基础】字符集与校对集详解6【MySQL基础】MySQL单表操作详解7【MySQL基础】运算符及相关函数详解文章目录前言MySQL多表操作1&#xff0c;多表关系1.1&#xff0c;一对一1.2&#xff0c;一对多1.3&#xff0c;多对多2&#…

Prometheus 配置身份认证

Prometheus 版本 2.41.0 平台统一监控的介绍和调研直观感受PromQL及其数据类型PromQL之选择器和运算符PromQL之函数Prometheus 配置身份认证 Prometheus 使用默认方式安装是不带有身份证认证和TLS&#xff0c;需要单独配置开启。 Prometheus 配置文件为yaml格式&#xff0c;并…

【自然语言处理】文本表示(一):One-Hot、BOW、TF-IDF、N-Gram

文本表示&#xff08;一&#xff09;&#xff1a;One-Hot、BOW、TF-IDF、N-Gram1.One-Hot 编码 One-Hot 编码&#xff0c;又称 “独热编码”&#xff0c;是比较常用的文本特征提取方法。这种方法把每个词表示为一个很长的向量。这个向量的维度是词表大小&#xff0c;只有一个维…

4. 基础语法

1. 标识符 a. 第一个字符必须是字母表中字母或下划线 _&#xff1b; b. 标识符的其他的部分由字母、数字和下划线组成&#xff1b; c. 标识符对大小写敏感&#xff1b; 在 Python 3 中&#xff0c;可以用中文作为变量名&#xff0c;非 ASCII 标识符也是允许的&#xff1b; 2.…

【JavaGuide面试总结】计算机网络·中

【JavaGuide面试总结】计算机网络中1.说说断开连接 - TCP 四次挥手2.为什么要四次挥手&#xff1f;3.为什么不能把服务器发送的 ACK 和 FIN 合并起来&#xff0c;变成三次挥手&#xff1f;4.如果第二次挥手时服务器的 ACK 没有送达客户端&#xff0c;会怎样&#xff1f;5.为什么…

第五届字节跳动青训营 前端进阶学习笔记(五)CSS进阶

文章目录前言CSS的重要特性1.选择器特指度&#xff08;1&#xff09;选择器优先级&#xff08;2&#xff09;选择器特指度2.继承&#xff08;1&#xff09;默认继承&#xff08;2&#xff09;显式继承3.初始值4.CSS属性值的计算过程布局&#xff08;Layout&#xff09;1.布局相…

搜索?——P3956 [NOIP2017 普及组] 棋盘

传送门: [NOIP2017 普及组] 棋盘 - 洛谷 思路: 将棋盘的每一个格子看做一个点&#xff0c;建一个无向图用来跑最短路. 这道题本应用搜索来做&#xff0c;但是转换成最短路好像简单点 建图: 1.对于已经有颜色的格子&#xff0c;在扫描四个方向的格子对相同颜色的建条长度为0…

【目标检测】目标检测究竟发展到了什么程度?聊聊这22年!

目录&#xff1a;目标检测的发展历程一、引言二、背景三、目标检测发展脉络3.1 传统目标检测算法3.1.1 Viola Jones Detector3.1.2 HOG Detector3.1.3 DPM Detector3.1.4 局限性3.2 Anchor-Based中的Two-stage目标检测算法3.2.1 RCNN3.2.2 SPPNet3.2.3 Fast RCNN3.2.4 Faster R…

Allegro如何设置Net Group操作指导

Allegro如何设置Net Group操作指导 Allegro除了可以对一组网络设置Bus以外,同样支持创建Net Group,如下图 功能和Bus的功能类似,并且同一个Net Group里面的网络可以形成一个shape形式的Group,方便查看 具体创建方法操作如下 打开规则管理器选择Electrical

MySQL窗口函教-开窗聚合函数(SUM()、AVG()、MAX()、MIN()、COUNT())

MySQL窗口函教-开窗聚合函数&#xff08;SUM()、AVG()、MAX()、MIN()、COUNT()&#xff09;和传统的聚合函数区别&#xff1f;最大的区别在于&#xff0c;一个操作列&#xff0c;一个是依次操作行&#xff0c;最终显示出每一行&#xff0c;最后的效果就是呈现叠加的效果-- 开窗…

Windows环境下安装配置Mosquitto服务及入门操作介绍

文章目录一、概念梳理二、下载与安装三、关于配置文件的一些重要说明四、配置登录账号和密码参考&#xff1a; 博客一、概念梳理 Mosquitto是一款实现了消息推送协议MQTT 3.1的开源消息代理软件&#xff0c;提供轻量级的、支持可订阅/可发布的消息推送模式&#xff0c;是设备与…

mf10ccwm芯片说明部分译文

MF10-N是一种通用的双二阶状态变量滤波器&#xff0c;其中心频率与应用于时钟输入&#xff08;fCLK&#xff09;的方波的频率成正比。通过将引脚12连接到适当的直流电压&#xff0c;滤波器中心频率fO可以等于fCLK/100或fCLK/50。通过使用晶体时钟振荡器可以非常精确地设置&…

《深入浅出计算机组成原理》学习笔记 Day5

动态链接1. 静态链接与动态链接2. 地址无关3. PLT 和 GOT参考1. 静态链接与动态链接 静态链接&#xff08;Static Link&#xff09;是通过合并代码段的方法来使程序装载至内存&#xff1b; 动态链接&#xff08;Dynamic Link&#xff09;则是链接加载到内存中的共享库&#xf…