SpringCache操作Redis

server/2024/9/20 7:26:23/ 标签: spring boot, java, redis, 后端, spring

 目录

(一)什么是SpringCache?

(二)解决了什么问题?

(三)如何使用SpringCache?


(一)什么是SpringCache?

SpringCache是一个由Spring提供的缓存框架,便于我们用注解的形式操作各种缓存

(二)解决了什么问题?

在开发中我们如果使用redis做缓存通常情况下就是,先查redis看数据是否存在如果没有查数据库然后写入到redis这一套代码大多数场景都要用到,这样就使重复冗余代码出现在项目的各个角落,并且如果我们将这些代码放在业务代码中也不好看,一旦改动我们就需要去业务代码里面做修改,所以SpringCache已注解的形式出现了,让我们轻轻松松完成缓存的操作。

(三)如何使用SpringCache?

1.引入依赖

java"><!--SpringCache依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><!--Redis依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

2.启动类添加注解开启SpringCache

java">@Slf4j
@SpringBootApplication
@EnableCaching//开启缓存功能
public class SpringBootApplicaitonMain {public static void main(String[] args) {SpringApplication.run(SpringBootApplicaitonMain.class,args);log.info("项目启动成功...");}
}

3.配置SpringCache操作的产品为Redis,因为SpringCache还可以操作其他缓存产品如Caffice或本地内存,这里我们指定为Redis,并且设置在使用SpringCache操作缓存时的过期时间(统一)

java">server:port: 8080
spring:redis:host: 172.17.2.94port: 6379password: root@123456database: 0cache:redis:time-to-live: 1800000 #设置缓存过期时间,可选

如果希望想有更细化的配置可以编写配置类

java">import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheErrorHandler;
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.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.*;import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.time.Duration;@Slf4j
@Configuration
@EnableCaching
@EnableConfigurationProperties(RedisProperties.class)
public class CacheConfig extends CachingConfigurerSupport {private static final FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);//缓存管理器。可以管理多个缓存//只有CacheManger才能扫描到cacheable注解//spring提供了缓存支持Cache接口,实现了很多个缓存类,其中包括RedisCache。但是我们需要对其进行配置,这里就是配置RedisCache@Beanpublic CacheManager cacheManager(RedisConnectionFactory connectionFactory) {RedisCacheManager cacheManager = RedisCacheManager.RedisCacheManagerBuilder//Redis链接工厂.fromConnectionFactory(connectionFactory)//缓存配置 通用配置  默认存储一小时.cacheDefaults(getCacheConfigurationWithTtl(Duration.ofHours(1)))//配置同步修改或删除  put/evict.transactionAware()//对于不同的cacheName我们可以设置不同的过期时间
//                .withCacheConfiguration("app:",getCacheConfigurationWithTtl(Duration.ofHours(5))).withCacheConfiguration("user:",getCacheConfigurationWithTtl(Duration.ofHours(2))).build();return cacheManager;}//缓存的基本配置对象private   RedisCacheConfiguration getCacheConfigurationWithTtl(Duration duration) {return RedisCacheConfiguration.defaultCacheConfig()//设置key value的序列化方式// 设置key为String.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))// 设置value 为自动转Json的Object.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer))// 不缓存null.disableCachingNullValues()// 设置缓存的过期时间.entryTtl(duration);}//缓存的异常处理@Bean@Overridepublic CacheErrorHandler errorHandler() {// 异常处理,当Redis发生异常时,打印日志,但是程序正常走log.info("初始化 -> [{}]", "Redis CacheErrorHandler");return new CacheErrorHandler() {@Overridepublic void handleCacheGetError(RuntimeException e, Cache cache, Object key) {log.error("Redis occur handleCacheGetError:key -> [{}]", key, e);}@Overridepublic void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);}@Overridepublic void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);}@Overridepublic void handleCacheClearError(RuntimeException e, Cache cache) {log.error("Redis occur handleCacheClearError:", e);}};}@Override@Bean("myKeyGenerator")public KeyGenerator keyGenerator() {return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {StringBuffer sb = new StringBuffer();sb.append(target.getClass().getName());sb.append(method.getName());for (Object obj : params) {sb.append(obj.toString());}return sb.toString();}};}}

4.注解@CachePut这个注解的作用就是在你添加数据时也就是新增时,将你添加的数据放到缓存中,通常用不到因为我们即使不添加到redis中,你经过一次查询也会写到redis里面,所以不用刻意添加。

        代码里面的value和key加起来就是你在redis里面的key至于redis里面的value就是你的返回值他会默认添加到redis里面,至于为什么value和key要分开写,你可以这样理解 用户user有很多种数据要缓存有身份信息、账户信息,那么他们都属于用户的数据所以叫value就是userCache但是还需要做区分所以可以在key里面进行区分,其实和redisKey的设计方式一样。

java">    @CachePut(value = "userCache", key = "user.id")@PostMappingpublic User save(User user) {userService.save(user);return user;}

5.注解@CacheEvict这个注解的作用就是删除的意思,当数据库发生变更如新增或者删除数据时,那么我们缓存是不是也要跟着变化,那么我们就可以把缓存删除掉让他为空,这样在查询时就可以从缓存中查询

java">    @CachePut(value = "userCache", key = "user.id")@PostMappingpublic User save(User user) {userService.save(user);return user;}

@CacheEvict还有这种情况就是批量删除或者你想删除这个key下面所有的缓存可以加上allEntries代表setmeallCache下面所有key的数据我都删除

java">   @DeleteMapping@CacheEvict(value = "setmealCache", allEntries = true)public R<String> delete(@RequestParam List<Long> ids) {log.info("ids:{}", ids);setmealService.deleteByIds(ids);return R.success(GlobalConstants.FINISHED);}

6.注解@Cacheable这个注解的作用就是先查缓存如果缓存没有查数据库然后写入到缓存

然后我们是已列表的形式添加数据我们想用ID做区分就可以从result也就是结果中获取ID,unless的意思是不满足这个条件我才执行缓存逻辑,什么意思呢就是你查询的结果result==null这是一个条件而unless就会把他取反当你result不为null时我才执行,与之对应的是condition满足条件我才执行,但是因为@Cacheable执行使用unless才能获取到结果result做判断,所以这里使用unless,添加这个的意思其实就是不想将null的数据添加到缓存

java">    @GetMapping("/list")@Cacheable(value = "setmealCache", key = "#result.setmeal.categoryId", unless = "result == null && result.size() == 0 ")public List<Setmeal> list(Setmeal setmeal) {LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(setmeal.getCategoryId() != null, Setmeal::getCategoryId, setmeal.getCategoryId());queryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, setmeal.getStatus());queryWrapper.orderByDesc(Setmeal::getUpdateTime);List<Setmeal> list = setmealService.list(queryWrapper);return list;}


http://www.ppmy.cn/server/104958.html

相关文章

Git 版本控制操作

1. 版本回退 Git 能够管理⽂件的历史版本&#xff0c;这是版本控制器重要的能⼒。如果有⼀天你发现之前前的⼯作做的出现了很⼤的问题&#xff0c;需要在某个特定的历史版本重新开始&#xff0c;这个时候&#xff0c;就需要版本回退的功能了。 执⾏ git reset 命令⽤于回退版…

ACCESS 工具注入实战 凡诺靶场

简介 Access数据库注入攻击是一种常见的网络安全&#xff0c;通过注入SQL代码来获取未授权的数据访问权限。这种攻击利用了应用程序与数据库之间的交互漏洞&#xff0c;攻击者通过输入特定的SQL代码片段来操纵数据库查询&#xff0c;从而绕过应用程序的安全机制&#xff0c;获取…

Go Convey测试框架入门(go convey gomonkey)

Go Convey测试框架入门 介绍 GoConvey是一款针对Golang的测试框架&#xff0c;可以管理和运行测试用例&#xff0c;同时提供了丰富的断言函数&#xff0c;并支持很多 Web 界面特性。 Golang虽然自带了单元测试功能&#xff0c;并且在GoConvey框架诞生之前也出现了许多第三方测…

第132天:内网安全-横向移动Exchange服务有账户CVE漏洞无账户口令爆破

域控环境0day.org 通过网盘分享的文件&#xff1a;131-0day.org内网域环境镜像文件 链接: https://pan.baidu.com/s/1rf_gHVJSNG8PEsiSr7DFSw?pwdr5jc 提取码: r5jc 给win7设置一张nat网卡&#xff0c;其他各个主机都设置为vm2 案例一&#xff1a; 域横向移动-内网服务-Exchan…

[kaggle竞赛] 毒蘑菇的二元预测

毒蘑菇的二元预测 您提供了很多关于不同二元分类任务的资源和链接&#xff0c;看起来这些都是Kaggle竞赛中的参考资料和高分解决方案。为了帮助您更好地利用这些资源&#xff0c;这里是一些关键点的总结&#xff1a; Playground Season 4 Episode 8 主要关注的竞赛: 使用银行…

Java ArrayList和LinkedList

ArrayList ArrayList是Java中最常用的数据结构之一&#xff0c;它是一个动态数组的实现&#xff0c;允许你在程序中存储和管理一个可变大小的对象列表&#xff0c;我们可以添加或删除元素。 ArrayList 继承了 AbstractList &#xff0c;并实现了 List 接口。 基本概念 Arra…

Git(面试篇)

目录 配置操作 全局配置 当前仓库配置 查看global配置 查看当前仓库配置 删除global配置 删除当前仓库配置 本地操作 查看变更情况 将当前目录及其子目录下所有变更都加入到暂存区 将仓库内所有变更都加入到暂存区 将指定文件添加到暂存区 比较工作区和暂存区的所有…

JavaScript学习文档(5):为什么需要函数、函数使用、函数传参、函数返回值、作用域、匿名函数、逻辑中断

目录 一、为什么需要函数 1、函数 2、说明 二、函数使用 1、函数的声明语法 2、函数名命名规范 3、函数调用语法 4、函数体 5、函数案例&#xff08;数字求和&#xff09; &#xff08;1&#xff09;计算1-100之间所有数字的和 三、函数传参 1、声明语法 2、调用语…

【Redis】Redis数据结构——List列表

List列表 命令lpushlpushxrpushrpushxlrangelpoprpoplindexlinsertllen 阻塞版本命令blpopbrpop 命令⼩结内部编码使用场景消息队列分频道的消息队列微博 Timeline 列表类型是⽤来存储多个有序的字符串&#xff0c;如图 2-19 所⽰&#xff0c;a、b、c、d、e 五个元素从左到右组…

Java 使用线程池和CountDownLatch分批插入或者更新数据

需求&#xff1a;在开发业务报表时&#xff0c;需要从MySQL数据库读取数据后进行操作&#xff0c;然后写入数据库&#xff0c;使用定时任务跑批。 分析&#xff1a;①兼顾性能&#xff0c;② MySQL没有Oracle那么方便、强大的存储过程。综上所述&#xff0c;使用线程池以分批提…

python dash框架 油气田可视化软件设计文档

V1.1:机器学习框架(神经网络) 时间范围优化 表格布局优化 添加前端设计元素布局 V1.0&#xff1a;基础布局和对应计算函数 要求 首先第一部分是通过神经网络预测天然气流量&#xff0c;其中输入开始时间和截止时间是为了显示这一段时间内的天然气流量预测结果 第二部分&…

前端实现首次访问,后续从本地访问

在前端实现将PDF文件下载到用户的本地磁盘&#xff0c;并在后续加载时使用本地文件&#xff0c;而不是重新从服务器下载&#xff0c;可以通过以下步骤实现&#xff1a; 1. **使用<a>标签的download属性**&#xff1a;当用户首次点击下载PDF时&#xff0c;通过<a>标…

私有仓库tomcat镜像构建

通过Tomcat安装包构建镜像 Dockerfile # 使用官方的OpenJDK镜像作为基础镜像 FROM xa-test.harbor.com:55555/idaas/openjdk:8u232 ENV CATALINA_HOME/usr/local/tomcat ENV PATH$CATALINA_HOME/bin:$PATH # 将Tomcat的压缩包复制到镜像中并解压到指定目录 COPY apache-tomcat…

Apollo9.0 PNC源码学习之Planning模块—— Lattice规划(六):横纵向运动轨迹评估

参考文章: (1)Apollo6.0代码Lattice算法详解——Part6:轨迹评估及碰撞检测对象构建 (2)自动驾驶规划理论与实践Lattice算法详解 0 前言 横纵向运动轨迹的评估,主要通过构建定点巡航和定点停车两个场景下,对纵向运动参考速度、加速度、加加速度的大小进行检验和过滤,然…

1.初识redis

文章目录 1.认识redis1.1 mysql和redis 对比1.2分布式系统1.2.1单机架构与分布式架构1.2.2数据库分离(应用服务器和存储服务器分离)与负载均衡1.2.3负载均衡器1.2.4 数据库读写分离1.2.5 数据库服务器引入缓存1.2.6数据库分库分表1.2.7 引入微服务 2.常见概念解释2.1 应用(Appl…

JDK15.0.2安装

JDK15.0.2安装 1. 下载 下载地址&#xff1a; https://www.oracle.com/java/technologies/downloads/archive/ 通过百度网盘分享的文件&#xff1a;jdk-15.0.2_windows-x64_bin.exe 链接&#xff1a;https://pan.baidu.com/s/15AOcTby3YLSp26_btCkEIw 提取码&#xff1a;vs7…

10. 指针数组和数组指针详细区别

指针数组和数组指针在存储位置和占用内存大小方面也有显著的区别&#xff0c;尤其是它们的结构不同导致内存分布上的差异。接下来详细说明它们在这两个方面的区别&#xff1a; 1. 指针数组 (Array of Pointers) 定义回顾&#xff1a; int *array[5];这里 array 是一个指针数…

K8S部署MySQL5.7的主从服务

mysql-slave-0是master mysql-slave-1是备份 当mysql写的时候&#xff0c;找headless service中的 mysql-slave-0.mysql57-slave-headless&#xff1b;当mysql读的时候&#xff0c;找clusterip service中的mysql57-slave-read读&#xff0c;实现读写分离。 statefulset维护两个…

Spring + Boot + Cloud + JDK8 + Elasticsearch 单节点 模式下实现全文检索高亮-分页显示 快速入门案例

1. 安装elasticsearchik分词器插件 sudo wget https://release.infinilabs.com/analysis-ik/stable/elasticsearch-analysis-ik-8.13.4.zip sudo mkdir -p ./es_plugins/analysis-ik sudo mkdir ./es_data sudo unzip elasticsearch-analysis-ik-8.13.4.zip -d ./es_plugins/a…

探索提示工程 Prompt Engineering的奥妙

一、探索提示工程 1. 介绍通用人工智能和专用人工智能 人工智能&#xff08;AI&#xff09;可以分为通用人工智能&#xff08;AGI&#xff09;和专用人工智能&#xff08;Narrow AI&#xff09;。AGI是一种能够理解、学习和执行任何人类可以完成的任务的智能。与此相对&#x…