设置公共请求参数_基于分布式锁的防止重复请求解决方案(值得收藏)

关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求。而这样的重复请求如果是幂等的(每次请求的结果都相同,如查询请求),那其实对于我们没有什么影响,但如果是非幂等的(每次请求都会对关键数据造成影响,如删除关系、建立关系等),那就会轻则产生脏数据,重则导致系统错误。

4529b3f752950dc1531c17524e4ecb48.png

因此,在当前普遍分布式服务的情况下,如何避免和解决重复请求给我们带来的数据异常成为了亟待解决的问题。而避免重复请求,最好的做法是前后端共同去做。

1. 前端或客户端在非幂等的按钮上直接做禁止提交重复请求的操作。

2. 后端在接收到请求时加锁,完成后解锁。

这篇博客主要讲的是在后端基于分布式锁的概念去出一个关于解决重复请求的通用解决方案。

二、正文

为何要使用分布式锁来解决呢?因为我们当前普遍的架构都是分布式的服务端,前端请求通过网关层转发至后端,如下图所示,因此如果只在一个单独的服务器上做限制,就无法在分布式的服务中完成应对高频次的重复请求了。

7c730d6dbffac5e87a1c113a14423fe5.png

基本思路

思路基本上是对需要做防止重复请求的接口加上分布式锁,步骤如下:

  1. 在接收到请求后,根据方法名+参数取md5值,获取该方法及该参数的唯一标识;
  2. 获取标识后设置分布式锁,并且设置过期时间;
  3. 在请求结束后,释放分布式锁。

即可完成对当前请求的重复请求禁止。如果想做通用的解决方案,那就需要把上述步骤做出一个小功能出来,由于本人对java、spring框架比较熟悉,就拿这个来做个示例。

基于spring切面、redis的实现

想必一些熟悉spring的同学已经知道我想采用什么方式了,做通用型的,肯定要用到spring的aop特性,注解+切面+md5key+反射+redis实现,具体如下:

  1. 定义一个分布式锁注解,注解包含过期时间设置、忽略参数;
  2. 定义一个切面,切点为分布式锁注解,在切面中获取需要使用分布式锁的方法名、参数、过期时间,并且将方法名及未被忽略参数做md5取唯一标识;
  3. 再根据上述唯一标识设置redsis分布式锁;
  4. 方法结束后解锁。
3456af7b2de0bd17d8f21ce3638a2a08.png

代码如下:

注解

定义名称为RepeatOperationLock的注解,参数有锁过期时间及忽略属性(即不参与分布式锁标识MD5计算的属性)。

@Documented@Inherited@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})@Componentpublic @interface RepeatOperationLock { /** * 锁时长,默认500ms * @return */ long timeOut() default 500; /** * 忽略上锁参数位置,从0开始 * @return */ int[] ignoreIndex();}复制代码

切面

切点为上述注解,切面中做了以下几件事,获取方法名、获取注解属性(过期时间、忽略属性)、计算方法+属性的md5值、调用外部分布式锁的方法。

@Aspect@Slf4j@Componentpublic class LockAspect { @Autowired RepeatLockService repeatLockService; @Pointcut("@annotation(com.ls.javabase.aspect.annotation.RepeatOperationLock)") public void serviceAspect() { } @Before("serviceAspect()") public void setLock(JoinPoint point) { log.info("防止方法重复调用接口锁,上锁,point:{}

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

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

相关文章

linux:vi 替换命令

:s/^.*$/\L&/100 ##将100行内的小写转换成大写 vi/vim 中可以使用 :s 命令来替换字符串。 :s/vivian/sky/ 替换当前行第一个 vivian 为 sky :s/vivian/sky/g 替换当前行所有 vivian 为 sky :n,$s/vivian/sky/ 替换第 n 行开始到最后一行中每一行的第…

[vue] 你有写过自定义指令吗?自定义指令的生命周期(钩子函数)有哪些?

[vue] 你有写过自定义指令吗?自定义指令的生命周期(钩子函数)有哪些? bind inserted update componentUpdated unbind个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。欢迎…

【niop2016】

D1T1 玩具谜题 my总结: 【luogu1563】【niop2016】玩具谜题 题面 模拟!!! D1T2 天天爱跑步 my总结: 暂无 题面 我太弱了还搞不出来 暴力也不想写 D1T3 换教室 my总结:【niop2016】【luogu1600】…

linux 复制文件或者文件

linux下文件的复制、移动与删除命令为:cp,mv,rm 一、文件复制命令cp 命令格式:cp [-adfilprsu] 源文件(source) 目标文件(destination) cp [option] source1 source2 source3 ... directory 参数说明&…

[vue] 你有看过vue的源码吗?如果有那就说说看

[vue] 你有看过vue的源码吗?如果有那就说说看 看过 看不懂个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

python的哪个模块提供了文件处理方法_Python处理文件路径有哪些方法?

在python中找寻路径的方法有很多,当然也有新方法在不断地更新中。对于新手的python小白来说,肯定是越简单越好用的最受欢迎。小编经过一番找寻,为大家带来两种方法,大家可以根据接受情况选择。老方法:Python的os.path模…

Linux 随机数

一、rand函数 rand函数的简单使用&#xff0c;rand()返回一个[0, RAND_MAX]中的随机数  #include <stdlib.h> #include <stdio.h> #include <time.h>int main() {printf("%d\n", RAND_MAX);//srand(time(NULL));for(int i 0; i < 5; i){print…

微信扫码支付

微信扫码支付&#xff08;laravel&#xff09; 1.未开通微信扫码支付 (1).参照微信扫码支付接入步骤 (2).开通成功之后用分配的商户号登录微信商户平台设置扫码支付的异步回调地址&#xff08;注意&#xff1a;是返给商户后台的回调地址&#xff09; 2.已经开通扫码支付 模…

[vue] 怎么使css样式只在当前组件中生效?

[vue] 怎么使css样式只在当前组件中生效&#xff1f; <style scoped> </style> 个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

linux 2行数据为一条记录 该如何操作这一条记录_Linux 日志文件系统原来是这样工作的...

文件系统要解决的一个关键问题是怎样防止掉电或系统崩溃造成数据损坏&#xff0c;在此类意外事件中&#xff0c;导致文件系统损坏的根本原因在于写文件不是原子操作&#xff0c;因为写文件涉及的不仅仅是用户数据&#xff0c;还涉及元数据(metadata)包括 Superblock、inode bit…

[vue] v-for循环中key有什么作用?

[vue] v-for循环中key有什么作用&#xff1f; 四个字: 性能优化,简述: 让vue在更新数据的时候可以更有针对性的个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

JMeter - 如何创建可重用和模块化测试脚本

概述&#xff1a; 我的应用程序几乎没有业务关键流程&#xff0c;我们可以从中提出不同的业务工作流程。当我试图在JMeter中提出性能测试脚本时&#xff0c;我需要找到一些方法来创建可重用/模块化的测试脚本。这样我就可以创建不同的工作流程。 对于Ex&#xff1a; 让我们考虑…

请求支付宝渠道报错:40006,Insufficient Permissions,ISV权限不足

错误描述&#xff1a; 申请的是支付宝2.0产品&#xff08;如何区分支付宝产品是1.0还是2.0&#xff09;&#xff0c;请求支付宝渠道时&#xff0c;报错&#xff1a; {"code":"40006","msg":"Insufficient Permissions","sub_code…

dll放在unity哪个文件夹下_unity中调用dll文件总结

unity中调用dll文件总结根据收集的资料&#xff0c;对unity中调用dll文件进行总结&#xff0c;目前常用的两种&#xff0c;在给出vs中封装dll文件的步骤。一、调用c#中的dll文件1.1封装dll文件首先新建一个项目然后创建一个类库&#xff0c;例如命名为Csharpusing System;using…

[vue] watch和计算属性有什么区别?

[vue] watch和计算属性有什么区别&#xff1f; 一个是侦听属性&#xff0c;一个是计算属性 2.一个是为了应对复杂的逻辑计算&#xff0c;一个是对数据的变化作出反应 3.一个是只有当缓存改变时才执行&#xff0c;一个是只要从新渲染就会执行 4.一个有缓存&#xff0c;一个没有…

如何将阿里云的数据库备份RDS文件在本地恢复

1.首先把RDS文件下载到本地&#xff0c;我的备份文件3.5G(下载时间6分钟)&#xff1b; 压缩包&#xff1a; hins2448103_data_20180127044633.tar.gz 2.解压下载的RDS压缩包&#xff1a; tar -xzvf hins2448103_data_20180127044633.tar.gz 解压完是一个一个的数据库文件夹…

idea中lombok的使用

1.安装插件 在File-Setting-Plugins-Browse Repostitories中搜索Lombok Plugin插件安装 安装完成先别急着重启&#xff0c;继续设置&#xff0c;在File-Setting-Build, Execution, Deployment-Compiler-Annotation Processors中点击Enable annotation processors 确定后重启ide…

是隐极电机_资料 | 发电机定子绕组端部动态特性试验详解

一、试验目的大型汽轮发电机运行过程中&#xff0c;定子端部受二倍工频(100Hz)的电磁激振力。如果定子端部的模态接近100Hz&#xff0c;将发生谐振&#xff0c;从而可能因振幅过大而发生结构松动、磨损、绝缘损坏等现象&#xff0c;甚至断裂等故障&#xff0c;严重威胁机组的安…

[vue] 为什么data属性必须声明为返回一个初始数据对应的函数呢?

[vue] 为什么data属性必须声明为返回一个初始数据对应的函数呢&#xff1f; 对象为引用类型&#xff0c;当重用组件时&#xff0c;由于数据对象都指向同一个data对象&#xff0c;当在一个组件中修改data时&#xff0c;其他重用的组件中的data会同时被修改&#xff1b;而使用返…

Mac系统xampp环境下安装redis和phpredis

一、安装redis服务 通过homebrew安装redis sudo brew install redis 安装Homebrew mac下redis简单命令 1.安装命令 brew install redis 2.启动Redis命令 redis-server /usr/local/etc/redis.conf 3.停止redis server服务 redis-cli shutdown 4.退出redis server服务 C…