当前位置: 首页 > news >正文

预防缓存穿透工具类

1. 前言

缓存穿透大家都知道,这里简单过一下

缓存和数据库中都没有的数据,而用户不断发起请求。比如查询id = -1 的值

想着很多面向C端的查询接口,可能都需要做一下缓存操作,这里简单写了个自定义注解,将查询结果(包含null值)做个缓存

这个只能预防单秒内接口高频次请求,要是一直搞随机值请求这个只能采取其他手段处理了(比如IP拉黑什么的…)

工具类留底,以后兴许可以直接抄~( ̄▽ ̄)"

2. 正文

直接上代码了

2.1 自定义注解

CacheResult

import java.lang.annotation.*;/*** <pre>* 接口缓存* 根据接口的第一个入参对象,和返回值进行缓存* 缓存的前缀为 TEMPORARY_CACHE:类名:方法名:key值* 示例:@CacheResult(key="userId + '_' + ecommerceId", seconds = 2L)* 缓存的key:TEMPORARY_CACHE:EcommerceController:getOrderList:407622341504839680_527203683850731520* </pre>* @author weiheng* @date 2023-08-25**/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface CacheResult {/** 入参支持 SpEL表达式 做参数提取,比如入参对象有属性userId和ecommerceId -> key="userId + '_' + ecommerceId" */String key();/** 缓存时长,单位:秒 */long seconds();
}

2.2 统一做缓存处理的切面

CacheAspect

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.api.RBucket;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;import javax.annotation.Resource;/*** 缓存统一处理* @author weiheng* @date 2023-08-25**/
@Slf4j
@Aspect
@Component
public class CacheAspect {/** 临时缓存的统一前缀 */public static final String DEFAULT_PREFIX = "TEMPORARY_CACHE:";/** 缓存分隔符 */public static final String DELIMITER = ":";@Resourceprivate RedissonHelper redissonHelper;/*** 拦截通知** @param proceedingJoinPoint 入参* @return Object*/@Around("@annotation(cacheSeconds)")public Object around(ProceedingJoinPoint proceedingJoinPoint, CacheResult cacheSeconds) {Object[] args = proceedingJoinPoint.getArgs();if (args.length == 0) {// 方法没有入参,不做缓存return proceed(proceedingJoinPoint);}// 1. 判断缓存中是否存在,有则直接返回Object firstArg = args[0];// 获取用户指定的参数ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = new StandardEvaluationContext(firstArg);Expression keyExpression = parser.parseExpression(cacheSeconds.key());String businessKey = keyExpression.getValue(context, String.class);// 拼装缓存keyString className = proceedingJoinPoint.getTarget().getClass().getSimpleName();String methodName = proceedingJoinPoint.getSignature().getName();String prefix = className + DELIMITER + methodName;String cacheKey = DEFAULT_PREFIX + prefix + DELIMITER + businessKey;RBucket<?> bucket = redissonHelper.getBucket(cacheKey);boolean exists = bucket.isExists();if (exists) {// 缓存中有值,直接返回return bucket.get();}// 2. 执行方法体Object returnValue = proceed(proceedingJoinPoint);// 3. 做个N秒的缓存long seconds = cacheSeconds.seconds();redissonHelper.setValueAndSeconds(cacheKey, returnValue, seconds);return returnValue;}private Object proceed(ProceedingJoinPoint proceedingJoinPoint) {Object returnValue;try {returnValue = proceedingJoinPoint.proceed();} catch (Throwable e) {log.error("error msg:", e);if (e instanceof SystemException) {throw (SystemException) e;}throw new SystemException(e.getMessage());}return returnValue;}

3. 使用示例

原本定义个2秒就OK了,这里为了方便看测试结果,给了60秒

@CacheResult(key=“userId + ‘_’ + ecommerceId”, seconds = 60L)

redis缓存如下:
在这里插入图片描述
就到这里了

相关文章:

预防缓存穿透工具类

1. 前言 缓存穿透大家都知道&#xff0c;这里简单过一下 缓存和数据库中都没有的数据&#xff0c;而用户不断发起请求。比如查询id -1 的值 想着很多面向C端的查询接口&#xff0c;可能都需要做一下缓存操作&#xff0c;这里简单写了个自定义注解&#xff0c;将查询结果(包含…...

会员管理系统实战开发教程04-会员开卡

我们已经用3篇篇幅介绍了会员管理的功能&#xff0c;接着就要开发会员的业务。通常我们开通会员之后需要给会员开通会员卡&#xff0c;一个会员可以有多张会员卡。 在数据源设计的时候&#xff0c;像这种一个会员有多张会员卡的&#xff0c;我们称之为一对多的关系&#xff0c…...

数据结构(2)

冒泡排序&#xff1a; 1.比较相邻的两个元素。如果前一个元素比后一个元素大&#xff0c;则交换两者位置。 2.对每一对相邻元素做相同工作&#xff0c;从第一对元素到最后一对元素&#xff0c;最后的一个元素就是最大的元素。 for(int ia.length-1;i>0;i--){for (int j 0…...

使用ELK(ES+Logstash+Filebeat+Kibana)收集nginx的日志

文章目录 Nginx日志格式修改配置logstash收集nginx日志引入Redis收集日志写入redis从redis中读取日志 引入FilebeatFilebeat简介Filebeat安装和配置 配置nginx转发ES和kibanaELK设置账号和密码 书接上回&#xff1a;《ELK中Logstash的基本配置和用法》 Nginx日志格式修改 默认…...

TDengine server连接遇到的坑

一、TDengine安装 TDengine目前只有linux版本的server端&#xff0c;安装教程参考 https://zhuanlan.zhihu.com/p/302413259 二、TDengine连接 TDengine连接目前支持两种方式&#xff0c;一种是原生连接&#xff0c;该方法的默认端口号为6030&#xff1b;另一种是REST API连…...

什么是NetDevOps

NetDevOps 是一种新兴的方法&#xff0c;它结合了 NetOps 和 DevOps 的流程&#xff0c;即将网络自动化集成到开发过程中。NetDevOps 的目标是将虚拟化、自动化和 API 集成到网络基础架构中&#xff0c;并实现开发和运营团队之间的无缝协作。 开发运营&#xff08;DevOps&…...

中小金融机构数字化转型最大的挑战是什么?

中国银保监会办公厅印发的《关于银行业保险业数字化转型的指导意见》强调&#xff0c;银行保险机构要加强顶层设计和统筹规划&#xff0c;科学制定数字化转型战略&#xff0c;统筹推进工作&#xff0c;并从战略规划与组织流程建设、业务经营管理数字化、数据能力建设、科技能力…...

Facebook HiPlot “让理解高维数据变得容易”

在这个全球信息化的时代&#xff0c;数据量呈爆炸式增长&#xff0c;数据的复杂性也是如此。如何有效地处理高维数据并找到隐藏在其中的相关性和模式是一个严峻的挑战。近年来&#xff0c;可视化和可视化分析已被应用于该任务&#xff0c;并取得了一些积极成果。Facebook的新Hi…...

【python】:python新设备环境移植(requirements.txt)

环境移植 condapip conda 你可以使用conda命令来创建一个包含所有已安装包的requirements.txt文件&#xff0c;并将其复制到新电脑上。然后&#xff0c;你可以在新电脑上使用pip命令来安装这些包及其依赖项。 以下是一个示例命令&#xff1a; conda list --export > requ…...

分类预测 | MATLAB实现1D-2D-CNN-GRU的多通道输入数据分类预测

分类预测 | MATLAB实现1D-2D-CNN-GRU的多通道输入数据分类预测 目录 分类预测 | MATLAB实现1D-2D-CNN-GRU的多通道输入数据分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 结合1D时序-2D图像多模态融合的CNN-GRU故障识别算法&#xff0c;基于一维时序信号和二维图…...

【LeetCode】125. 验证回文串 - 双指针

这里写自定义目录标题 2023-8-24 09:31:12 125. 验证回文串 2023-8-24 09:31:12 最关键的是 注意 题目中的 “字母和数字都属于字母数字字符。” 使用ascii码进行判断就行了 class Solution {public boolean isPalindrome(String s) {int p 0, q s.length() - 1;while (…...

centos7设置java后端项目开机自启【脚本、开机自启】

1.切换目录 cd /etc/init.d/2.编辑脚本 vim wbs-service-start.sh编辑内容 #!/bin/bash # chkconfig: 2345 80 90 # description: auto_runnohup java -jar /usr/java/wbs-service.jar > /dev/null 2>&1 & echo $! > /var/run/wbs-service.pid3.添加进入系…...

亿赛通电子文档安全管理系统 RCE漏洞复现(QVD-2023-19262)

0x01 产品简介 亿赛通电子文档安全管理系统&#xff08;简称&#xff1a;CDG&#xff09;是一款电子文档安全加密软件&#xff0c;该系统利用驱动层透明加密技术&#xff0c;通过对电子文档的加密保护&#xff0c;防止内部员工泄密和外部人员非法窃取企业核心重要数据资产&…...

一文读懂 Nuxt.js 服务端组件

服务端组件在 Web 开发生态系统中变得越来越普遍。传统上&#xff0c;在单页面应用中&#xff0c;即使是服务端渲染的应用&#xff0c;服务端仅与第一次加载相关&#xff0c;之后将由客户端接管。这意味着 Web 应用的每个部分都必须能够在客户端和服务端上渲染。 相反&#xf…...

LeetCode--HOT100题(39)

目录 题目描述&#xff1a;101. 对称二叉树&#xff08;简单&#xff09;题目接口解题思路代码 PS: 题目描述&#xff1a;101. 对称二叉树&#xff08;简单&#xff09; 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 LeetCode做题链接&#xff1a;LeetCode-…...

“车-路-网”电动汽车充电负荷时空分布预测(matlab)

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序参考《基于动态交通信息的电动汽车充电负荷时空分布预测》和《基于动态交通信息的电动汽车充电需求预测模型及其对配网的影响分析》文献模型&#xff0c;考虑私家车、出租车和共用车三类交通工具特性和…...

【核磁共振成像】方格化重建

目录 一、缩放比例二、方格化变换的基础三、重建时间四、方格化核 一、缩放比例 对于笛卡尔K空间直线轨迹数据可直接用FFT重建&#xff0c;而如果K空间轨迹的任何部分都是非均匀取样的 可用DFT直接重建&#xff0c;有时称为共轭相位重建&#xff0c;但此法太慢不实用。把数据再…...

JAVA中时间戳和LocalDateTime的互转

时间戳转LocalDateTime&#xff1a; 要将时间戳转换为LocalDateTime并将LocalDateTime转换回时间戳&#xff0c;使用Java的java.time包。以下是示例代码&#xff1a; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId;public class Times…...

无涯教程-进程 - 创建终止

到现在为止&#xff0c;我们知道无论何时执行程序&#xff0c;都会创建一个进程&#xff0c;并且该进程将在执行完成后终止&#xff0c;如果我们需要在程序中创建一个进程&#xff0c;并且可能希望为其安排其他任务&#xff0c;该怎么办。能做到吗?是的&#xff0c;显然是通过…...

LLMs参考资料第一周以及BloombergGPT特定领域的训练 Domain-specific training: BloombergGPT

1. 第1周资源 以下是本周视频中讨论的研究论文的链接。您不需要理解这些论文中讨论的所有技术细节 - 您已经看到了您需要回答讲座视频中的测验的最重要的要点。 然而&#xff0c;如果您想更仔细地查看原始研究&#xff0c;您可以通过以下链接阅读这些论文和文章。 1.1 Trans…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事&#xff0c;必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后&#xff0c;我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集&#xff0c;就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...