【redis】ssm项目整合redis,redis注解式缓存及应用场景,redis的击穿、穿透、雪崩的解决方案

 一、整合redis

 redis是nosql数据库,mysql是sql数据库,都是数据库因此可以参考mysql整合ssm项目的过程。

1.pom依赖

  <properties>    <redis.version>2.9.0</redis.version><redis.spring.version>1.7.1.RELEASE</redis.spring.version></properties><dependencies><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>${redis.version}</version></dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>${redis.spring.version}</version></dependency></dependencies>

2 spring-redis.xml 

  1. 注册 redis.properties
  2. 配置数据源
  3. 连接工厂
  4. 配置序列化
  5. 配置redis的key生成策略
<?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="300"/><!--连接池的最大数据库连接数  --><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>

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

3 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注解式开发

首先需要一个缓冲策略类,用于储存信息

package com.xzs.ssm.redis;import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.util.ClassUtils;import java.lang.reflect.Array;
import java.lang.reflect.Method;@Slf4j
public class CacheKeyGenerator implements KeyGenerator {// custom cache keypublic static final int NO_PARAM_KEY = 0;public static final int NULL_PARAM_KEY = 53;@Overridepublic Object generate(Object target, Method method, Object... params) {StringBuilder key = new StringBuilder();key.append(target.getClass().getSimpleName()).append(".").append(method.getName()).append(":");if (params.length == 0) {key.append(NO_PARAM_KEY);} else {int count = 0;for (Object param : params) {if (0 != count) {//参数之间用,进行分隔key.append(',');}if (param == null) {key.append(NULL_PARAM_KEY);} else if (ClassUtils.isPrimitiveArray(param.getClass())) {int length = Array.getLength(param);for (int i = 0; i < length; i++) {key.append(Array.get(param, i));key.append(',');}} else if (ClassUtils.isPrimitiveOrWrapper(param.getClass()) || param instanceof String) {key.append(param);} else {//Java一定要重写hashCode和eqaulskey.append(param.hashCode());}count++;}}String finalKey = key.toString();
//        IEDA要安装lombok插件log.debug("using cache key={}", finalKey);return finalKey;}
}

1 Cacheable 注解

1、定义查询接口使用Cacheable注解

Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果。

package com.xzs.ssm.biz;import com.zking.ssm.model.Clazz;
import com.zking.ssm.util.PageBean;import org.springframework.cache.annotation.Cacheable;import java.util.List;
import java.util.Map;public interface ClazzBiz {@Cacheable("clz")Clazz selectByPrimaryKey(Integer cid);}

  2、编写测试类

package com.xzs.shiro;import com.zking.ssm.biz.ClazzBiz;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:applicationContext.xml"})
public class ClazzBizTest {@Autowiredprivate ClazzBiz clazzBiz;@Testpublic void test1(){System.out.println(clazzBiz.selectByPrimaryKey(10));System.out.println(clazzBiz.selectByPrimaryKey(10));}}

第一次运行时:(查询两次)

第二次运行时:(无查询语句)

再次运行相同的数据时不再查询了,直接从缓冲中拿取数据:

2 自定义策略 

@Cacheable可以指定三个属性,value、key和condition。 

我可定义key值来修改我们保存到redis缓冲的key值,并且可通过condition来制定什么时候需要缓冲,进一步优化性能。

自定义策略,如果查询的cid大于6才进行缓冲 

package com.xzs.ssm.biz;import com.zking.ssm.model.Clazz;
import com.zking.ssm.util.PageBean;import org.springframework.cache.annotation.Cacheable;import java.util.List;
import java.util.Map;public interface ClazzBiz {@Cacheable(value = "clz",key = "'cid:'+#cid",condition = "#cid > 6")Clazz selectByPrimaryKey(Integer cid);}

 3 CachePut 注解 

它的使用与Cacheable的使用一致,它们的区别:

  • Cacheable:会在redis中存储数据,同时也会读取数据
  • CachePut:只会在redis储存数据,不会进行读取操作
  • package com.xzs.ssm.biz;import com.zking.ssm.model.Clazz;
    import com.zking.ssm.util.PageBean;import org.springframework.cache.annotation.Cacheable;import java.util.List;
    import java.util.Map;public interface ClazzBiz {@CachePut(value = "clz",key = "'cid:'+#cid",condition = "#cid > 6")Clazz selectByPrimaryKey(Integer cid);}

    测试:

    public class ClazzBizTest {@Autowiredprivate ClazzBiz clazzBiz;@Testpublic void test1(){System.out.println(clazzBiz.selectByPrimaryKey(9));System.out.println(clazzBiz.selectByPrimaryKey(9));}}

不管运行多少次,它还是会查询数据库,即便已经将数据存储到redis中 

三、Redis中缓冲、击穿、穿透、雪崩问题解决 

1 缓冲问题 —— Quartz 框架 

        现在模拟一个场景:我在某系统中增加了一条数据,在主界面中会显示该条数据。而数据是从缓冲中拿取的,而新增的数据并没有立即添加到缓冲中。那我们如何保证redis数据与数据库数据的一致性呢?

方案一:手动刷新数据同步策略

        这样我们每次添加了新的数据,需要手动点击刷新缓冲键,显然这个对管理者不便的。

方案二:利用Quartz作业调度框架,定时刷新任务

   Quartz是一个开源的作业调度框架,用于在Java应用程序中实现任务调度和定时任务管理。它提供了一种简单而强大的方式来安排和执行各种类型的作业,包括定时任务、周期性任务和异步任务。

        Quartz框架的核心概念是作业(Job)和触发器(Trigger)。作业是要执行的任务,而触发器定义了作业执行的时间和频率。通过配置作业和触发器,可以实现灵活的任务调度和执行。

在Redis中,它本身并没有直接使用Quartz框架。然而,我们可以结合使用Quartz和Redis来实现一些特定的功能,例如:

使用Quartz调度任务,将任务的执行结果存储到Redis中,以便其他系统或模块可以读取和处理。
使用Quartz定时清理Redis中的过期数据,以确保Redis的存储空间得到有效利用。
使用Quartz定时刷新Redis中的缓存数据,以保持数据的最新性。
使用Quartz和Redis实现分布式锁机制,确保在多个节点上的任务调度不会发生冲突。
 

 2 常见的三种问题解决方案 

1、击穿(Cache Miss) 击穿指的是在高并发情况下,当一个缓存键(key)不存在于缓存中,但是被大量请求同时查询时,这些请求会直接访问数据库,导致数据库压力过大。这种情况下,缓存无法发挥作用,而且数据库可能会因此而崩溃。

解决方案:

  • 使用互斥锁(Mutex Lock)或分布式锁(Distributed Lock)来保护数据库访问,确保只有一个请求能够访问数据库,其他请求等待结果。
  • 在缓存中设置短暂的空值(Null Value),以防止大量请求同时查询同一个缓存键。

2、穿透(Cache Penetration) 穿透指的是当一个缓存键不存在于缓存中,并且被大量请求同时查询时,这些请求都会直接访问数据库,导致数据库压力过大。与击穿不同的是,穿透是因为查询的键根本不存在于缓存中。

解决方案:

在查询数据库之前,可以添加一个布隆过滤器(Bloom Filter)来快速判断查询的键是否存在于缓存中。如果不存在,可以直接返回空结果,而不是访问数据库。
对于查询结果为空的情况,也可以将空结果缓存一段时间,以避免频繁查询数据库。
 

 3、雪崩(Cache Avalanche) 雪崩指的是在缓存中大量的缓存键同时过期或失效,导致大量请求直接访问数据库,造成数据库压力过大,甚至崩溃。

解决方案:

设置缓存键的过期时间时,可以引入随机值,使得缓存键的过期时间分散开来,避免大量缓存键同时过期。
使用热点数据预加载(Cache Pre-warming)策略,提前加载热门数据到缓存中,减少缓存键同时失效的可能性。
使用多级缓存架构,将缓存分为多个层级,以降低整体缓存失效的风险。

总结: 在解决这些问题时,我们需要综合考虑系统的并发性、可用性和性能。通过合理的缓存策略、锁机制、预加载与使用调度框架等手段,可以有效地解决Redis中的击穿、穿透和雪崩问题,提高系统的稳定性和性能。 

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

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

相关文章

C++——搜索二叉树

作者&#xff1a;几冬雪来 时间&#xff1a;2023年11月7日 内容&#xff1a;C的搜索二叉树讲解 目录 前言&#xff1a; 什么是搜索二叉树&#xff1a; 搜索二叉树的增删查改&#xff1a; 搜索二叉树的定义初始化&#xff1a; 搜索二叉树增操作&#xff1a; 搜索二叉树找…

目前安卓、鸿蒙、澎湃的关系

1、了解AOSP是什么 AOSP全名为Android Open-Source Project&#xff0c;中文为安卓开源项目&#xff0c;开源即开放源代码。Android是一个基于Linux&#xff0c;由Google主导的开源系统。 2、AOSP谁的贡献最大&#xff1f; 3、华为的鸿蒙、小米的澎湃是套壳安卓吗&#xff1…

QGC 中添加海康威视摄像头记录(Qt For Android 使用 JNI 进行JAVA 与 C++ 的通讯)

文章目录 1. 配置海康威视 SDK 下载库文件移植工程文件添加动态库&#xff08;.so&#xff09;Android xml 配置添加 java 文件 2. JavaQGCActivity.javaHkwsManager.java 3. C头文件添加&#xff1a;C 中调用 Java 静态函数&#xff08;hcnNetSDKInit&#xff09;JNI 传入规则…

JJJ:PCI / PCIE 的一些术语和概念

转发事务和非转发事务 在PCIe&#xff08;Peripheral Component Interconnect Express&#xff09;总线中&#xff0c;存在两种类型的事务&#xff1a;转发事务和非转发事务。 1、转发事务&#xff08;Forwarded Transactions&#xff09;&#xff1a;转发事务是指从一个PCIe…

11 传输层协议

1、传输层里比较重要的两个协议&#xff0c;一个是 TCP&#xff0c;一个是UDP 对于不从事底层开发的人员来讲&#xff0c;或者对于开发应用的人来讲&#xff0c;最常用的就是这两个协议。 2、TCP 和 UDP 有哪些区别&#xff1f; 1.TCP 是面向连接的&#xff0c;UDP 是面向无…

P1903 [国家集训队] 数颜色 / 维护队列

带修改的莫队 带修改的莫队就是在基础莫队的基础上增加了一维属性&#xff0c;之前只需要维护l&#xff0c;r现在还需要维护一下时间t&#xff0c;排序还是先按照左端点块儿号排序&#xff0c;然后右端点块儿号排序&#xff0c;最后按时间排序。其它的都是差不多的。 #include…

无人机航迹规划:小龙虾优化算法COA求解无人机路径规划MATLAB(可以修改起始点,地图可自动生成)

一、小龙虾优化算法COA 小龙虾优化算法&#xff08;Crayfsh optimization algorithm&#xff0c;COA&#xff09;由Jia Heming 等人于2023年提出&#xff0c;该算法模拟小龙虾的避暑、竞争和觅食行为&#xff0c;具有搜索速度快&#xff0c;搜索能力强&#xff0c;能够有效平衡…

掌握未来技术趋势:深度学习与量子计算的融合

掌握未来技术趋势&#xff1a;深度学习与量子计算的融合 摘要&#xff1a;本博客将探讨深度学习与量子计算融合的未来趋势&#xff0c;分析这两大技术领域结合带来的潜力和挑战。通过具体案例和技术细节&#xff0c;我们将一睹这两大技术在人工智能、药物研发和金融科技等领域…

Maven多环境下 active: @profileActive@报错问题解决

1.报错&#xff1a; Caused by: org.yaml.snakeyaml.scanner.ScannerException: while scanning for the next token found character that cannot start any token.(Do not use for indentation) 2.解决办法&#xff1a; 在主pom的文件下&#xff0c;重新加载&#xff1a;

软件测试-根据状态迁移图设计测试用例

测试用例状态迁移图 许多需求用状态机的方式来描述&#xff0c;状态机的测试主要关注状态转移是否正确。对于一个有限状态机&#xff0c;通过测试验证其在给定的条件内是否能够产生需要的状态变化&#xff0c;有没有不可达的状态和非法的状态&#xff0c;是否可能产生非法的状…

newstarctf2022week2

Word-For-You(2 Gen) 和week1 的界面一样不过当时我写题的时候出了个小插曲 连接 MySQL 失败: Access denied for user rootlocalhost 这句话印在了背景&#xff0c;后来再进就没了&#xff0c;我猜测是报错注入 想办法传参 可以看到一个name2,试着传参 发现有回显三个字段…

51基于matlab模拟退火算法矩形排样

基于matlab模拟退火算法矩形排样&#xff0c;基于最低水平线算法完成矩形板材下料优化&#xff0c;输出最优剩料率和最后的水平线&#xff0c;可替换自己的数据进行优化&#xff0c;程序已调通&#xff0c;可直接运行。 51matlab模拟退火算法矩形排样 (xiaohongshu.com)

Unity 实现文字过长显示省略号

为了整体效果&#xff0c;当文字过长时&#xff0c;我们就会把超出范围的文字弄成省略号。 要实现文字过长显示省略号&#xff0c;只需要使用TextMeshPro&#xff0c;并设置Overflow属性为Ellipsis即可。 如下图&#xff1a; 记。

【广州华锐互动】VR综合布线虚拟实验教学系统

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐渗透到各个领域&#xff0c;为人们的生活和工作带来了前所未有的便利。在建筑行业中&#xff0c;VR技术的应用也日益广泛&#xff0c;尤其是在综合布线方面。 广州华锐互动开发的VR综合布线虚拟实…

【Git】Git基础命令操作速记

【Git】Git基础命令操作速记 文章目录 【Git】Git基础命令操作速记1. 初始化1.1 设置用户名和邮箱1.2 初始化仓库 2. 基础命令2.1 add和commit2.2 reset2.3 查看日志2.4 删除/找回本地仓库文件2.5 找回暂存区文件2.6 diff命令(找不同) 3. 分支命令3.1 查看分支3.2 创建分支3.3 …

ArcGIS Pro设置谷歌影像(无水印)

1 打开软件&#xff0c;命名工程文件&#xff0c;底图&#xff08;Basemap&#xff09;选择【天地图】。 2 点击【视图&#xff08;View&#xff09;】——>【目录面板&#xff08;Catalog pane&#xff09;】&#xff0c;在【门户&#xff08;Portal&#xff09;】中搜索【…

redis: 记录一次线上redis内存占用过大问题解决过程

引言 记录一次线上redis占用过大的排查过程&#xff0c;供后续参考 问题背景 测试同事突然反馈测试环境的web系统无法登陆&#xff0c;同时发现其他子系统也存在各类使用问题 排查过程 1、因为首先反馈的是测试环境系统无法登陆&#xff0c;于是首先去查看了登陆功能的报错…

Linux 进程控制

进程地址空间的收尾 task_struct有一个结构体成员叫mm_struct&#xff0c;也就是进程地址空间。 为什么要有进程地址空间&#xff1a;进程内存地址管理&#xff0c;保护物理内存&#xff0c;进行权限审查&#xff0c;从无序变有序&#xff0c;让我们从统一的视角看待进程代码…

ModuleNotFoundError: No module named ‘torchvision.models.utils‘

如图报错&#xff1a;No module named torchvision.models.utils解决方案&#xff1a;由于当前python环境高版本的torch&#xff0c; 代码用的是低版本的语法 将 from torchvision.models.utils import load_state_dict_from_url换成 from torch.hub import load_state_dict_fr…

数据结构与算法—插入排序选择排序

目录 一、排序的概念 二、插入排序 1、直接插入排序 直接插入排序的特性总结&#xff1a; 2、希尔排序 希尔排序的特性总结&#xff1a; 三、选择排序 1、直接选择排序 时间复杂度 2、堆排序—排升序(建大堆) 向下调整函数 堆排序函数 四、交换排序 1、冒泡排…