“Redis与Spring整合及缓存优化“
文章目录
- 引言
- 1. Spring整合Redis
- 1.1. 为什么选择Redis作为缓存解决方案?
- Redis的特点和优势
- Redis与传统关系数据库的对比
- 1.2. Spring与Redis整合的基本步骤
- 2. Redis注解式缓存
- 2.1. Spring提供的缓存注解介绍
- 2.2. 使用注解实现方法级别的缓存
- 3. Redis的击穿、穿透和雪崩问题及解决方案
- 3.1. 几种常见的Redis缓存问题
- 3.2. 解决方案和优化策略
- 总结

引言
在现代应用开发中,缓存是提升性能和扩展性的关键技术之一。而Redis作为一种高性能、内存存储型数据库,与Spring框架的结合可以带来更加优雅和灵活的缓存解决方案。本篇博客将深入探讨Spring整合Redis的方法和最佳实践,并重点介绍Redis注解式缓存以及解决常见的Redis问题。
1. Spring整合Redis
1.1. 为什么选择Redis作为缓存解决方案?
Redis的特点和优势
-
内存存储:Redis将数据存储在内存中,因此具有非常高的读写速度。相比传统数据库的磁盘存储,Redis能够快速处理大量请求。
-
键值存储:Redis使用键值对(key-value)的数据结构来存储数据。这种简单的数据模型使得数据操作非常高效和灵活,适用于各种场景。
-
支持多种数据类型:Redis支持丰富的数据类型,包括字符串、哈希、列表、集合、有序集合等。这些数据类型的支持使得开发者可以更方便地构建复杂的应用逻辑。
-
缓存功能:Redis常被用作缓存服务器,可以将频繁访问的数据存储在内存中,从而加快数据读取速度。同时,Redis还提供了一些高级的缓存策略,如过期时间、LRU淘汰等。
-
发布订阅系统:Redis提供了发布订阅(pub/sub)功能,允许客户端通过订阅某个频道来接收消息的推送。这种消息发布订阅模式对于实时通信、消息队列等场景非常有用。
-
分布式支持:Redis支持分布式部署,可以将数据分布在多个节点上进行存储和访问。这种分布式的特性使得Redis具备高可用性和横向扩展的能力。
Redis与传统关系数据库的对比
-
数据模型:Redis采用键值对的数据模型,而传统关系数据库使用表格模型。这使得Redis在处理简单查询和高并发读写方面更加高效,而关系数据库更适合复杂的数据关联和查询操作。
-
存储方式:Redis将数据存储在内存中,而关系数据库通常将数据持久化到磁盘中。因此,Redis在读写速度方面更快,但关系数据库在数据持久化和容量方面具有优势。
-
功能特性:Redis提供了丰富的功能特性,如发布订阅、缓存策略等,而关系数据库更加注重数据一致性、事务管理以及复杂的查询能力。
-
扩展性:Redis支持分布式部署和横向扩展,可以通过添加新的节点来提高性能和容量。而关系数据库通常需要进行垂直扩展,即增加更强大的硬件来应对高负载。
-
数据一致性:Redis默认情况下是单机的,不保证数据的强一致性,而关系数据库通常会保证数据的一致性。
1.2. Spring与Redis整合的基本步骤
准备步骤:
- 打开redis服务
- 导入spring整合redis项目
- 当spring-context.xml文件需要注册多个.properties结尾的配置文件,不能在spring-*中添加注册
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!--1. 引入外部多文件方式 --><bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" /><property name="ignoreResourceNotFound" value="true" /><property name="locations"><list><value>classpath:jdbc.properties</value><value>classpath:redis.properties</value></list></property></bean><!-- 随着后续学习,框架会越学越多,不能将所有的框架配置,放到同一个配制间,否者不便于管理 --><import resource="applicationContext-mybatis.xml"></import><import resource="spring-redis.xml"></import><import resource="applicationContext-shiro.xml"></import>
</beans>
redis.properties
redis.hostName=localhost
redis.port=6379
redis.password=123456
redis.timeout=10000
redis.maxIdle=300
redis.maxTotal=1000
redis.maxWaitMillis=1000
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.testOnBorrow=true
redis.testWhileIdle=true
redis.expiration=3600
spring-redis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:cache="http://www.springframework.org/schema/cache"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/cachehttp://www.springframework.org/schema/cache/spring-cache.xsd"><!-- 1. 引入properties配置文件 --><!--<context:property-placeholder location="classpath:redis.properties" />--><!-- 2. redis连接池配置--><bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"><!--最大空闲数--><property name="maxIdle" value="${redis.maxIdle}"/><!--连接池的最大数据库连接数 --><property name="maxTotal" value="${redis.maxTotal}"/><!--最大建立连接等待时间--><property name="maxWaitMillis" value="${redis.maxWaitMillis}"/><!--逐出连接的最小空闲时间 默认1800000毫秒(30分钟)--><property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"/><!--每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3--><property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"/><!--逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1--><property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"/><!--是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个--><property name="testOnBorrow" value="${redis.testOnBorrow}"/><!--在空闲时检查有效性, 默认false --><property name="testWhileIdle" value="${redis.testWhileIdle}"/></bean><!-- 3. redis连接工厂 --><bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"destroy-method="destroy"><property name="poolConfig" ref="poolConfig"/><!--IP地址 --><property name="hostName" value="${redis.hostName}"/><!--端口号 --><property name="port" value="${redis.port}"/><!--如果Redis设置有密码 --><property name="password" value="${redis.password}"/><!--客户端超时时间单位是毫秒 --><property name="timeout" value="${redis.timeout}"/></bean><!-- 4. redis操作模板,使用该对象可以操作redishibernate课程中hibernatetemplete,相当于session,专门操作数据库。--><bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"><property name="connectionFactory" ref="connectionFactory"/><!--如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!! --><property name="keySerializer"><bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/></property><property name="valueSerializer"><bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/></property><property name="hashKeySerializer"><bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/></property><property name="hashValueSerializer"><bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/></property><!--开启事务 --><property name="enableTransactionSupport" value="true"/></bean><!-- 5.配置缓存管理器 --><bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"><constructor-arg name="redisOperations" ref="redisTemplate"/><!--redis缓存数据过期时间单位秒--><property name="defaultExpiration" value="${redis.expiration}"/><!--是否使用缓存前缀,与cachePrefix相关--><property name="usePrefix" value="true"/><!--配置缓存前缀名称--><property name="cachePrefix"><bean class="org.springframework.data.redis.cache.DefaultRedisCachePrefix"><constructor-arg index="0" value="-cache-"/></bean></property></bean><!--6.配置缓存生成键名的生成规则--><bean id="cacheKeyGenerator" class="com.zking.ssm.redis.CacheKeyGenerator"></bean><!--7.启用缓存注解功能--><cache:annotation-driven cache-manager="redisCacheManager" key-generator="cacheKeyGenerator"/>
</beans>
- resources的配置文件的配置必须要涵盖读取.properties结尾的文件
- redisTemplate的使用,可以参照jdbcTemplate、amqpTemplate、rabbitMQtemplate等
2. Redis注解式缓存
2.1. Spring提供的缓存注解介绍
package com.zking.ssm.biz;import com.zking.ssm.model.Clazz;
import com.zking.ssm.util.PageBean;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;import java.util.List;
import java.util.Map;public interface ClazzBiz {@CacheEvict(value = "xx",key = "'cid:'+#cid",allEntries = true)int deleteByPrimaryKey(Integer cid);int insert(Clazz record);int insertSelective(Clazz record);// xx=cache-cid:1
// key的作用改变原有的key生成规则
// @Cacheable(value = "xx",key = "'cid:'+#cid",condition = "#cid > 6")@CachePut(value = "xx",key = "'cid:'+#cid",condition = "#cid > 6")Clazz selectByPrimaryKey(Integer cid);int updateByPrimaryKeySelective(Clazz record);int updateByPrimaryKey(Clazz record);List<Clazz> listPager(Clazz clazz, PageBean pageBean);List<Map> listMapPager(Clazz clazz, PageBean pageBean);
}
@Cacheable:缓存方法的返回值,可读写
@CachePut:更新缓存的方法,只写不读,适合读写分离
@CacheEvict:移除缓存中的数据
2.2. 使用注解实现方法级别的缓存
在Spring Boot项目中开启注解式缓存
定义缓存的Key和Value的生成策略
编写示例代码演示注解式缓存的使用方式
3. Redis的击穿、穿透和雪崩问题及解决方案
3.1. 几种常见的Redis缓存问题
击穿:大量请求同时查询一个不存在的Key,导致请求都落到数据库上
穿透:恶意请求查询一个不存在的Key,导致请求直接落到数据库上
雪崩:大量缓存失效导致所有请求都落到数据库上
3.2. 解决方案和优化策略
击穿解决方案:设置热点数据永不过期、互斥锁、布隆过滤器等
穿透解决方案:空值缓存、参数校验、布隆过滤器等
雪崩解决方案:限流、降级、异步更新缓存等
总结
在本篇博客中,我们深入探讨了Redis与Spring的整合以及注解式缓存的使用方式。通过学习和实践,我们了解了Redis作为一种高性能缓存解决方案的优势,并且掌握了基于Spring框架使用Redis的方法。
相关文章:

“Redis与Spring整合及缓存优化“
文章目录 引言1. Spring整合Redis1.1. 为什么选择Redis作为缓存解决方案?Redis的特点和优势Redis与传统关系数据库的对比 1.2. Spring与Redis整合的基本步骤 2. Redis注解式缓存2.1. Spring提供的缓存注解介绍2.2. 使用注解实现方法级别的缓存 3. Redis的击穿、穿透…...

腾讯云3年云服务器价格及购买教程
腾讯云作为国内领先的云计算服务提供商,提供了多种优惠的云服务器套餐,以满足不同用户的需求,本文将详细介绍腾讯云3年云服务器价格及购买教程,新老用户均可购买! 1、活动页面:传送门>>> 2、进入…...

cortex-A7核 中断实验(按键中断实验)
1.选择按键触发方式 下降沿 2.解决消抖的方法 1)ARM中:延时消抖 2)linux驱动开发:定时器函数 3.框图 内部流程框图: 需要RCC GPIO EXTI GIC章节 中断触发流程: 4.RCC 章节 1)使能GPIOF组 …...

.NET Framework中自带的泛型委托Action
Action<>是.NET Framework中自带的泛型委托,可以接收一个或多个输入参数,但不返回任何参数,可传递至多16种不同类型的参数类型。在Linq的一些方法上使用的比较多。 1、Action泛型委托 .NET Framework为我们提供了多达16个参数的Action…...

DAIR-V2X-V 3D检测数据集 转为Kitti格式 | 可视化
本文分享在DAIR-V2X-V数据集中,将标签转为Kitti格式,并可视化3D检测效果。 一、将标签转为Kitti格式 DAIR-V2X包括不同类型的数据集: DAIR-V2X-IDAIR-V2X-VDAIR-V2X-CV2X-Seq-SPDV2X-Seq-TFDDAIR-V2X-C-Example: google_drive_linkV2X-Seq-…...

深入理解指针:【探索指针的高级概念和应用二】
目录 一,数组参数、指针参数 1.一维数组传参 2.二维数组传参 3.一级指针传参 4.二级指针传参 二,函数指针 三,函数指针数组 🍂函数指针数组的用途(转移表): 四,指向函数指针…...

腾讯觅影数智医疗影像平台获颁世界互联网领先科技成果大奖
11月8日,2023年世界互联网大会乌镇峰会在乌镇举行,腾讯再度获颁“世界互联网领先科技成果”大奖。腾讯健康总裁吴文达在世界互联网领先科技成果发布活动中介绍,“腾讯觅影数智医疗影像平台”已全面开放20多个医疗AI引擎助力科研创新ÿ…...

鸿蒙开发工具DevEco Studio的下载和安装
一、DevEco Studio概述 1、简介 HUAWEI DevEco Studio(获取工具请单击链接下载,以下简称DevEco Studio)是基于IntelliJ IDEA Community开源版本打造,为运行在HarmonyOS和OpenHarmony系统上的应用和服务(以下简称应用…...

【原理篇】四、自定义starter
文章目录 1、案例分析2、业务功能的实现3、中途调试4、开启定时任务打印报表5、引入属性配置类,写活业务参数配置6、拦截器7、开启yml提示功能 做一个记录系统访客独立IP访问次数的功能,并把它自定义成一个starter,实现:在现有项目…...

redisTemplate不支持zpopmax,解决方案使用reverseRangeWithScore
在redis客户端可以使用zpopmax redisTemplate不支持zpopmax 解决方案 使用reverseRangeWithScore 接下来我们进行测试 我们要返回最大的value,应该是c import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.a…...

基于深度模型的日志异常检测
本文转载自:深度模型的日志异常检测,还有谁不会?PPT下载地址:https://bbs.huaweicloud.com/forum/thread-100052-1-1.html视频讲解地址:https://bbs.huaweicloud.com/live/DevRun_live/202101222000.html 文章目录 1. …...

最大连续子数组
最大连续子数组(Maximum Subarray)问题是一个经典的算法问题,其目标是在给定的整数数组中找到一个连续的子数组,使得该子数组的元素之和最大。这个问题有多种解决方法,其中包括暴力解法、分治法和动态规划等。 下面是…...

【FastCAE源码阅读5】使用VTK实现鼠标拾取对象并高亮
鼠标拾取对象是很多软件的基本功能。FastCAE的拾取比较简单,是通过VTK实现的。 对几何而言,拾取类型切换在工具栏上,单击后再来单击视图区对象进行拾取,拾取后的对象会高亮显示。效果如下图: 一、拾取对象 拾取对象…...

【全志H616 使用标准库 完成自制串口库(分文件实现) orangepi zero2(开源)】.md updata: 23/11/07
文章目录 H616 把玩注意:Linux内核版本5.16 及以上,需手动配置i2c-3 uart5驱动配置示例 分文件编译时需将每个文件一同编译 (空格隔开)例: ggc a.c b.c b.h -lpthread -lxxx..; 常用命令查看驱动文件查看内核检测信息/…...

小白学爬虫:手机app分享商品短连接获取淘宝商品链接接口|淘宝淘口令接口|淘宝真实商品链接接口|淘宝商品详情接口
通过手机APP分享的商品短链接,我们可以调用相应的接口来获取淘口令真实URL,进而获取到PC端的商品链接及商品ID。具体步骤如下: 1、通过手机APP分享至PC端的短链接,调用“item_password”接口。 2、该接口将返回淘口令真实URL。 3…...
python 应用之 request 请求调用
场景: 验证一个第三方接口 目录 一、应用实例 1、预准备工作 1)、引用包 2)、生成随机串 3)、获得当前时间戳 4)、HASH 5)、header处理 6)、请求处理 2、requests请求 1)…...

BeanUtils.copyProperties浅拷贝的坑你得知道?
今天想写一篇文章,主要关于深拷贝和浅拷贝相关的,主要是最近写代码的时候遇到一个BUG,刚好涉及到浅拷贝导致的问题。 问题背景 现在有一个需要是需要修改门店信息,门店也区分父门店和子门店,父门店被编辑更新是需要通过…...
ubuntu安装rabbitMQ 并 开启记录消息的日志
apt-get update apt-get install rabbitmq-server rabbitmqctl add_user root password // 设置用户名密码 rabbitmqctl set_user_tags root administrator // 设置为管理员身份 rabbitmqctl set_permissions -p / root ".*" ".*" ".*" //为…...

思维模型 首因效应
本系列文章 主要是 分享 思维模型,涉及各个领域,重在提升认知。先入为主,一见钟情。 1 首因效应的应用 1.1 面试中的首因效应 小李是一名应届毕业生,他准备参加一家知名互联网公司的面试。在面试前,他做了充分的准备…...

Redis极速上手开发手册【Redis全面复习】
文章目录 什么是RedisRedis的特点Redis的应用场景Redis安装部署Redis基础命令Redis多数据库特性Redis数据类型Redis数据类型之stringRedis数据类型之hashRedis数据类型之listRedis数据类型之setRedis数据类型之sorted set案例:存储高一班的学员信息 Redis封装工具类…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...

ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章 摘要: 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言,受限于 C 语言本身的内存安全和并发安全问题,开发复杂模块极易引入难以…...