Redis缓存配置

redis缓存

使用redis缓存的原因是因为在可能的高并发环境下,mysql数据库无法承受大量的请求,可能会导致数据库崩溃。而这些请求很大一部分都是查询请求,因此采用redis这样的以内存作为存储数据空间的数据库来存储查询请求的数据,这样既提高了查询的效率,又分担了一大部分请求并发的压力。

具体实现使用了AOP面向切面编程的思想,即使用@PointCut注解指定切面,在本项目中就是指定各类控制器中的各种方法,并且以**@Around注解代表的环绕方式**进行切入。利用简单类名加方法名加参数名作为缓存的键cacheKey,方法得到的值作为键的值。对于一个查询请求类型的方法执行前先在redis中查询cacheKey,如果没有则在redis中设置这个cacheKey和值以及过期时间,设置过期时间的原因是因为redis是基于内存存储数据,因此需要定期清理数据。如果有cacheKey则直接从redis中获取值。对于除了查询类型以外的方法,则先删除当前控制器下的所有缓存键,避免缓存无法更新的问题,然后再去数据库进行查询,并返回结果。

在这个过程中,可能会遇到缓存击穿,缓存穿透,缓存雪崩的问题。

因为所谓的缓存击穿,就是一个承受着高并发请求的键,因为过期时间到了,cacheKey就失效了,这时候高并发的请求会涌入mysql数据库,就像大量的请求击穿了缓存一样,因此叫做缓存击穿嘛。在本项目中解决的方案为当cacheKey不存在时,进入数据库中查询的行为使用syncronize锁住,并且使用双检锁确保只有一个线程能进入数据库查询,这样即使高并发请求的key失效也不会造成大量的请求涌入mysql数据库了,就解决了缓存击穿的问题。但是因为此项目没有高并发的用户访问,属于内部操作管理系统,所以使用syncronize已足够。

而面向高并发用户的系统使用syncronize来锁就不能解决分布式服务器的问题,因为syncronize和lock只能锁住本地JVM的线程,无法锁住其他服务器中的线程,因此在那种情况下应该采用分布式锁,而分布式锁的实现比较常见的有两种方案,一种为zookeeper实现,一种是redis实现,实现原理为请求访问时使用SETNX命令向redis中存储一个具有过期时间的key,如果成功设置则上锁成功,如果设置失败则进入阻塞。由于分布式服务器使用的是同一个redis数据库,所以就能达到互斥的效果。

而对于缓存雪崩的问题,由于缓存雪崩就是多个key同时过期导致大量查询请求进入数据库,所以在设置键的过期时间的时候精确到微妙或纳秒级别,这样就可以避免大量键同时过期的问题。

对于缓存穿透的问题,也就是解决用户利用查询数据库不存在的数据进行恶意攻击的行为,本项目中是即使数据库中查出数据可能为空,但是也添加到缓存中,这样再次查询就会查出缓存中的空而不是进入mysql数据库中查。

@Aspect
@Component
public class RedisCacheAspect {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;private final Random random = new Random();//    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")@Pointcut("execution(* com.stt.cms.*.controller..*(..))")private void pointcut(){}@Around("pointcut()")public Object around(ProceedingJoinPoint pjp) throws Throwable {Signature signature = pjp.getSignature(); //获取连接点的签名MethodSignature ms = (MethodSignature) signature;//因为在spring aop中,连接点的类型都是方法,因此,这个签名就是一个方法的签名Method method = ms.getMethod();//从方法签名中获取方法String className = method.getDeclaringClass().getSimpleName();if (method.isAnnotationPresent(GetMapping.class)) {//如果方法上存在GetMapping注解,说明这个方法就是一个查询方法// 检查是否是上传或下载方法if (method.getName().startsWith("upload") || method.getName().startsWith("download")) {return pjp.proceed(); // 直接执行方法,不进行缓存}//需要将返回结果放入redis缓存中,方便下一次查询的时候使用Object[] args = pjp.getArgs();String methodName = method.getName();String cacheKey = className + "::" + methodName + JSON.toJSONString(args);//首先去校验缓存中是否存在我们需要获取的数据if (Boolean.TRUE.equals(redisTemplate.hasKey(cacheKey))) {//如果缓存中存在,那么就说明获取的数据就是返回值return redisTemplate.opsForValue().get(cacheKey);} else {//考虑到并发问题,这里需要上锁进行处理synchronized (this){ //这里的双检锁就是为了解决缓存击穿问题的//如果redis中不存在缓存if(Boolean.FALSE.equals(redisTemplate.hasKey(cacheKey))){//缓存中没有数据Object result = pjp.proceed(); //执行方法得到的返回结果//这里的过期时间要设置为随机过期时间,防止缓存雪崩,但是需要注意的是,随机时间是小单位的//随机,不能是大单位的随机long expire = Duration.ofMinutes(5).toNanos() + random.nextInt(1000);redisTemplate.opsForValue().set(cacheKey, result, expire, TimeUnit.NANOSECONDS);return result;}  else {return redisTemplate.opsForValue().get(cacheKey);}}}//这里还需要考虑缓击穿和缓存存穿透问题} else {//其余情况我们只需要考虑增删改带来的缓存失效问题的处理if(method.isAnnotationPresent(PostMapping.class)|| method.isAnnotationPresent(PutMapping.class)||method.isAnnotationPresent(DeleteMapping.class)){//这里需要考虑去删除缓存,从而更新缓存List<String> cacheKeys = redisTemplate.execute((RedisCallback<List<String>>) connection -> {ScanOptions scanOptions = ScanOptions.scanOptions().match(className + "*").count(50).build();List<String> keys = new ArrayList<>();Cursor<byte[]> cursor = connection.scan(scanOptions);while (cursor.hasNext()) {byte[] next = cursor.next();String scanKey = new String(next);System.err.println("扫描到失效的键:" + scanKey);keys.add(scanKey);}return keys;});if(cacheKeys != null)redisTemplate.delete(cacheKeys);}return pjp.proceed();}}
}

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

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

相关文章

springboot静态资源访问问题归纳

以下内容基于springboot 2.3.4.RELEASE 1、默认配置的springboot项目&#xff0c;有四个静态资源文件夹&#xff0c;它们是有优先级的&#xff0c;如下&#xff1a; "classpath:/META-INF/resources/", &#xff08;优先级最高&#xff09; "classpath:/reso…

【Android】android,震动一下,50ms,震动等级设置低一点

要在Android中实现震动50ms,并将震动等级设置为低,你可以使用Vibrator类。下面是一个简单的代码示例,展示如何实现这个功能: import android.content.Context; import android.os.VibrationEffect; import android.os.Vibrator

React+Vis.js(03):设置节点形状

文章目录 Vis支持的形状类型代码实现完整代码实现效果Vis支持的形状类型 circle(圆形)box(盒子)dot(点)star(五角星)triangle(三角形)ellipse(椭圆形)triangleDown(倒三角形)diamond(菱形)代码实现 通过shape属性来定义每个节点的形状 const nodes = new vis…

Unified 阻抗控制 architecture、framework、approach

Unified 阻抗控制&#xff08;Unified Impedance Control&#xff09;作为一种控制策略&#xff0c;其architecture&#xff08;架构&#xff09;、framework&#xff08;框架&#xff09;和approach&#xff08;方法&#xff09;为&#xff1a; 一、Unified 阻抗控制 Archite…

骨板和螺钉市场分析:前五大厂商占有大约78.0%的市场份额

据QYResearch调研团队最新报告“全球骨板和螺钉市场报告2024-2030”显示&#xff0c;预计2030年全球骨板和螺钉市场规模将达到76.2亿美元&#xff0c;未来几年年复合增长率CAGR为3.7%。 根据QYResearch头部企业研究中心调研&#xff0c;全球范围内骨板和螺钉生产商主要包括J &a…

视频美颜SDK与直播美颜工具的开发详解与技术优化

本篇文章&#xff0c;小编将为开发者提供一份详细的美颜指南。 一、视频美颜SDK的核心功能 视频美颜SDK是一种嵌入式软件开发工具包&#xff0c;允许开发者在应用中轻松实现实时美颜效果。其核心功能主要包括&#xff1a; 1.实时磨皮 2.美白功能 3.瘦脸与大眼 4.智能滤镜…

AWS 消息队列服务 SQS

AWS 消息队列服务 SQS 引言什么是 SQSSQS 访问策略 Access Policy示例&#xff1a;如何为 DataLake Subscription 配置 SQS 引言 应用系统需要处理海量数据&#xff0c;数据发送方和数据消费方是通过什么方式来无缝集成消费数据的&#xff0c;AWS 提供 SQS 消息队列服务来解决…

设计模式21-组合模式

设计模式21-组合模式&#xff08;Composite Pattern&#xff09; 写在前面 动机定义与结构定义结构主要类及其关系 C代码推导优缺点应用场景总结补充叶子节点不重载这三个方法叶子节点重载这三个方法结论 写在前面 数据结构模式 常常有一些组件在内部具有特定的数据结构。如何…

相机光学(三十四)——色差仪颜色观察者视角

1.为什么会有观察者视角 颜色观察角度主要涉及到人眼观察物体时&#xff0c;‌视角的大小以及屏幕显示颜色的方向性对颜色感知的影响。‌ 人眼观察物体的视角&#xff1a;‌在黑暗条件下&#xff0c;‌人眼主要依靠杆体细胞来分辨物体的轮廓&#xff0c;‌而杆体细胞分布在视网…

牛客网SQL进阶135 :每个6/7级用户活跃情况

每个67级用户活跃情况_牛客题霸_牛客网 0 问题描述 基于用户信息表user_info、、试卷作答记录表exam_record、题目练习记录表practice_record&#xff0c;统计 每个6/7级用户总活跃月份数、2021年活跃天数、2021年试卷作答活跃天数、2021年答题活跃天数&#xff0c;结果 按照总…

在linux上架设Web服务器Apache(Ubuntu)

欢迎诸位来阅读在下的博文~ 在这里&#xff0c;在下会不定期发表一些浅薄的知识和经验&#xff0c;望诸位能与在下多多交流&#xff0c;共同努力! 江山如画&#xff0c;客心如若&#xff0c;欢迎到访&#xff0c;一展风采 文章目录 背景1. 安装 Apache2. 启动和检查 Apache 服务…

常用的分类算法及其优缺点

常用的分类算法包括决策树、朴素贝叶斯、支持向量机&#xff08;SVM&#xff09;、K-近邻&#xff08;KNN&#xff09;、逻辑回归以及神经网络等。每种算法都有其独特的优点和缺点&#xff0c;适用于不同的场景和需求。以下是这些常用分类算法的优缺点概述&#xff1a; 1. 决策…

微信群自动发消息机器人:智能管理,高效沟通的新篇章

在快节奏的现代生活中&#xff0c;微信群已成为我们日常交流、信息分享的重要平台。然而&#xff0c;随着群内成员的增加和消息量的激增&#xff0c;如何高效、精准地传达信息&#xff0c;成为了许多群主和管理员面临的难题。此时&#xff0c;微信群自动发消息机器人的出现&…

强烈推荐这三款IOS应用,让你的生活更美好

Dino记账 Dino记账是一款结合了简洁设计和强大功能的记账应用&#xff0c;它通过多维度图表帮助用户轻松掌握金钱流向。应用界面明亮且配色突出&#xff0c;使得记录内容易于阅读&#xff0c;让记账和管理账目变得更加简单。 主要特性&#xff1a; 极简风格与易用性&#xff1…

掌握 Spring Boot + MyBatis-Plus 动态数据源切换,只要5分钟!

数据量猛增&#xff0c;通过动态数据源切换&#xff0c;我们不仅能提高查询效率&#xff0c;还能保证系统的高可用性。 通过将写操作集中在主库&#xff0c;读操作分散到多个从库&#xff0c;可以有效减轻数据库的压力。 在pom.xml中添加以下依赖&#xff1a; xml <depend…

Qt系统机制

Qt系统 Qt文件概述输入输出设备类QFileQFileInfoQt多线程Qt多线程常用API使用Qt多线程 线程安全互斥锁读写锁条件变量信号量 Qt网络QUdpSocketQNetworkDatagram设计一个UDP回显服务器QTcpServerQTcpSocketTcp版本的回显服务器HttpClient核心API Qt 音频Qt视频 Qt文件概述 ⽂件操…

如何优化淘客返利系统中的前端性能与用户体验

如何优化淘客返利系统中的前端性能与用户体验 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;是个冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们来讨论如何优化淘客返利系统中的前端性能与用户体验。良好的前端性能和用户体验不仅能够提升用户…

入门Pandas必练习100题基础到进阶|阶级教程2

作者:郭震 51. How to get the row number of the nth largest value in a column? Find the row position of the 5th largest value of column a in df. # input df pd.DataFrame(np.random.randint(1, 30, 30).reshape(10,-1), columnslist(abc)) df# Solution 1# argsort…

HEML+CSS超详细基础知识

一些快捷键 ctrl/ 是注释 ctrld 是选中多个相同字 ctrls保存 altZ自动换行 altshift选中多行 HTML认知 基础认知 html初尝试 HTML页面结构介绍 初次尝试 开始动手写一个网页 先新建一个文件&#xff0c;记得后缀要命名成html 然后shift&#xff01;&#xff0c;就会自动…

《系统架构设计师教程(第2版)》第13章-层次式架构设计理论与实践-01-层次式体系结构概述

文章目录 1. 常用层次是架构2. 层次式架构设计的注意点2.1 污水池反模式2.2 应用变得庞大 本章教材又赘述了一遍架构的定义和层次架构风格的概述&#xff0c;我之前的笔记都写了 架构的定义回看《第7章-系统架构设计基础知识-01-软件架构&#xff08;Software Architecture&…