分布式防止重复请求或者高并发防止重复提交

1:自定义注解JRepeat

package com.huan.study.mybatis.config;import java.lang.annotation.*;/*** 防止重复提交的注解**/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface JRepeat {/*** 超时时间** @return*/int lockTime();/*** redis 锁key的** @return redis 锁key*/String lockKey() default "";}

2:自定义切面

package com.huan.study.mybatis.aspect;/*** @author zyf*/import com.huan.study.mybatis.config.JRepeat;
import com.huan.study.mybatis.config.RedissonLockClient;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.TimeUnit;/*** 防止重复提交分布式锁拦截器**/
@Aspect
@Component
public class RepeatSubmitAspect extends BaseAspect {@Resourceprivate RedissonLockClient redissonLockClient;/**** 定义controller切入点拦截规则,拦截JRepeat注解的业务方法*/@Pointcut("@annotation(jRepeat)")public void pointCut(JRepeat jRepeat) {}/*** AOP分布式锁拦截** @param joinPoint* @return* @throws Exception*/@Around("pointCut(jRepeat)")public Object repeatSubmit(ProceedingJoinPoint joinPoint,JRepeat jRepeat) throws Throwable {String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(((MethodSignature) joinPoint.getSignature()).getMethod());if (Objects.nonNull(jRepeat)) {// 获取参数Object[] args = joinPoint.getArgs();// 进行一些参数的处理,比如获取订单号,操作人id等StringBuffer lockKeyBuffer = new StringBuffer();String key =getValueBySpEL(jRepeat.lockKey(), parameterNames, args,"RepeatSubmit").get(0);// 公平加锁,lockTime后锁自动释放boolean isLocked = false;try {isLocked = redissonLockClient.fairLock(key, TimeUnit.SECONDS, jRepeat.lockTime());// 如果成功获取到锁就继续执行if (isLocked) {// 执行进程return joinPoint.proceed();} else {// 未获取到锁throw new RuntimeException("请勿重复提交");}} finally {// 如果锁还存在,在方法执行完成后,释放锁if (isLocked) {redissonLockClient.unlock(key);}}}return joinPoint.proceed();}
}
package com.huan.study.mybatis.aspect;import lombok.extern.slf4j.Slf4j;
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 java.util.ArrayList;
import java.util.List;@Slf4j
public class BaseAspect {/*** 通过spring SpEL 获取参数** @param key            定义的key值 以#开头 例如:#user* @param parameterNames 形参* @param values         形参值* @param keyConstant    key的常亮* @return*/public List<String> getValueBySpEL(String key, String[] parameterNames, Object[] values, String keyConstant) {List<String> keys = new ArrayList<>();if (!key.contains("#")) {String s = "redis:lock:" + key + keyConstant;log.debug("lockKey:" + s);keys.add(s);return keys;}//spel解析器ExpressionParser parser = new SpelExpressionParser();//spel上下文EvaluationContext context = new StandardEvaluationContext();for (int i = 0; i < parameterNames.length; i++) {context.setVariable(parameterNames[i], values[i]);}Expression expression = parser.parseExpression(key);Object value = expression.getValue(context);if (value != null) {if (value instanceof List) {List value1 = (List) value;for (Object o : value1) {addKeys(keys, o, keyConstant);}} else if (value.getClass().isArray()) {Object[] obj = (Object[]) value;for (Object o : obj) {addKeys(keys, o, keyConstant);}} else {addKeys(keys, value, keyConstant);}}log.info("表达式key={},value={}", key, keys);return keys;}private void addKeys(List<String> keys, Object o, String keyConstant) {keys.add("redis:lock:" + o.toString() + keyConstant);}
}

3:自定义RedissonLockClient

package com.huan.study.mybatis.config;import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;/*** 分布式锁实现基于Redisson** @author zyf* @date 2020-11-11*/
@Slf4j
@Component
public class RedissonLockClient {@Autowiredprivate RedissonClient redissonClient;@Resourceprivate RedisTemplate<String, Object> redisTemplate;/*** 获取锁*/public RLock getLock(String lockKey) {return redissonClient.getLock(lockKey);}/*** 加锁操作** @return boolean*/public boolean tryLock(String lockName, long expireSeconds) {return tryLock(lockName, 0, expireSeconds);}/*** 加锁操作** @return boolean*/public boolean tryLock(String lockName, long waitTime, long expireSeconds) {RLock rLock = getLock(lockName);boolean getLock = false;try {getLock = rLock.tryLock(waitTime, expireSeconds, TimeUnit.SECONDS);if (getLock) {log.info("获取锁成功,lockName={}", lockName);} else {log.info("获取锁失败,lockName={}", lockName);}} catch (InterruptedException e) {log.error("获取式锁异常,lockName=" + lockName, e);getLock = false;}return getLock;}public boolean fairLock(String lockKey, TimeUnit unit, int leaseTime) {RLock fairLock = redissonClient.getFairLock(lockKey);try {boolean existKey = existKey(lockKey);// 已经存在了,就直接返回if (existKey) {return false;}return fairLock.tryLock(3, leaseTime, unit);} catch (InterruptedException e) {e.printStackTrace();}return false;}public boolean existKey(String key) {return redisTemplate.hasKey(key);}/*** 锁lockKey** @param lockKey* @return*/public RLock lock(String lockKey) {RLock lock = getLock(lockKey);lock.lock();return lock;}/*** 锁lockKey** @param lockKey* @param leaseTime* @return*/public RLock lock(String lockKey, long leaseTime) {RLock lock = getLock(lockKey);lock.lock(leaseTime, TimeUnit.SECONDS);return lock;}/*** 解锁** @param lockName 锁名称*/public void unlock(String lockName) {try {redissonClient.getLock(lockName).unlock();} catch (Exception e) {log.error("解锁异常,lockName=" + lockName, e);}}
}

4:demo所著相同请求5秒,如果方法执行完成释放

    @SneakyThrows@GetMapping("test")@JRepeat(lockKey = "#phone", lockTime = 5)public void test(String phone) {new Thread(() -> {try {// 尝试获取锁,最多等待10秒,获取锁后10秒自动释放System.out.println(new Date() + Thread.currentThread().getName() + " 获取到锁,开始处理任务...");Thread.sleep(10000); // 模拟处理任务需要花费一些时间System.out.println(new Date() + Thread.currentThread().getName() + " 处理任务完成,释放锁...");} catch (InterruptedException e) {e.printStackTrace();}}).start();System.out.println("===" + new Date());}

5:yml配置redis

spring:redis:database: 0host: 127.0.0.1password: 123456port: 6379

注意:因为是基于AOP切面,如果在方法内,调用的方法上添加该注解会失效

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

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

相关文章

通过龙讯旷腾PWmat发《The Journal of Chemical Physics》 :基于第一性原理分子动力学热力学积分的离子溶剂化自由能计算

背景导读 离子溶解是电化学中一个重要的过程。电化学反应中许多重要的参数&#xff0c;例如电化学还原电位、无限稀释活度系数、亨利定律溶解常数和离子溶解度等&#xff0c;都与离子的溶剂化能有关。然而&#xff0c;由于测量技术和数据处理的困难&#xff0c;离子溶剂化能的…

vCenter7.0安装部署

vCenter7.0安装部署 一、准备环境二、创建新的虚拟机1.创建虚拟机2.第3-5步可直接默认安装并同意许可协议。3.其他设置4.第一阶段直接点完成即可 三、进入第二阶段安装&#xff08;输入ip&#xff1a;5480进入安装界面&#xff09; 一、准备环境 准备一台exsi&#xff0c;并登…

【定义动态组件】

利用动态组件可以动态切换页面中现实的组件&#xff0c;使用标签可以定义动态组件&#xff0c;语法格式如下。 <component is "要渲染的组件"></component>在上述语法中&#xff0c;标签必须配合is属性一起使用&#xff0c;is属性属性值表示要渲染组件&…

MySQL之查询性能优化(九)

查询性能优化 MySQL查询优化器的局限性 UNION的限制 有时&#xff0c;MySQL无法将限制条件从外层"下推"到内层&#xff0c;这使得原本能够限制部分返回结果的条件无法应用到内层查询的优化上。如果希望UNION的各个子句能够根据LIMIT只取部分结果集&#xff0c;或者…

项目沟通管理

目录 1.概述 2.项目沟通的重要性和必要性 2.1.项目沟通的重要性 2.2.项目沟通的必要性 2.3.具体措施 3.三个过程 3.1.规划沟通管理 3.2.管理沟通 3.3.监督沟通 3.4.对应过程组 4.应用场景 4.1.十个应用场景 4.2.新产品开发项目需要与多个部门协调沟通 5.总结 1.概…

调节效应多元统计回归

什么是调节效应&#xff0c;给个例子说明一下: 背景 假设我们有一个国家的经济数据&#xff0c;我们希望研究产业数字化是否调节了环境规制对产业结构调整的影响。 步骤 1. 假设检验 原假设 (H0)&#xff1a; 产业数字化对环境规制与产业结构调整之间的关系没有调节作用。…

C++ | 类对象初始化

文章目录 概述一、定义介绍二、操作教程1.直接初始化&#xff08;Direct Initialization&#xff09;2.复制初始化&#xff08;Copy Initialization&#xff09;3.列表初始化&#xff08;List Initialization&#xff09; 概述 本节介绍类对象初始化。 一、定义介绍 在C中通过…

银河麒麟V10_系统如何自定义添加桌面右键菜单选项

本篇博客取自《银河麒麟桌面操作系统软件适配常见问题指导手册》官网可以下载。 环境 系统版本 适用系统&#xff1a;V10&#xff08;SP1&#xff09;适用架构&#xff1a;X86、ARM、MIPS 其他版本和架构可做参考。 解决方案 使用下面的这个demo 编译就可以看到效果 peony…

每日一题——Python实现PAT甲级1063 Set Similarity(举一反三+思想解读+逐步优化)

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 优点 改进建议 时间复杂度分析 空间复杂度分析 总结 我要更强 优化方…

【C语言】指针(4)

一、回顾 在这之前&#xff0c;我们学习了很多关于指针的内容&#xff0c;我们先在这里简单的回顾一下。 1、一级指针 int* p; -- 整形指针-指向整形的指针 char* p; ... void* p;... ... 2、二级指针 int** p; char** p; ... 3、数组指针 -- 指向数组的指针 int (*p)[ ]…

3038. 相同分数的最大操作数目 I(Rust模拟击败100%Rust用户)

题目 给你一个整数数组 nums &#xff0c;如果 nums 至少 包含 2 个元素&#xff0c;你可以执行以下操作&#xff1a; 选择 nums 中的前两个元素并将它们删除。 一次操作的 分数 是被删除元素的和。 在确保 所有操作分数相同 的前提下&#xff0c;请你求出 最多 能进行多少次…

在 Vue 中实现算法可视化

算法是计算机科学的核心&#xff0c;而算法可视化有助于更好地理解算法的运行过程。本文将介绍如何在 Vue.js 中实现算法可视化&#xff0c;以排序算法为例&#xff0c;逐步展示数据变化过程。 环境搭建 首先&#xff0c;确保你已安装 Vue CLI&#xff0c;可以使用以下命令创…

Python | Leetcode Python题解之第136题只出现一次的数字

题目&#xff1a; 题解&#xff1a; class Solution:def singleNumber(self, nums: List[int]) -> int:return reduce(lambda x, y: x ^ y, nums)

Vue07-MVVM模型

一、MVVM模型的定义 M&#xff1a;模型&#xff08;model&#xff09;&#xff1a;对应data中的数据&#xff1b;V&#xff1a;视图&#xff08;view&#xff09;&#xff1a;模版&#xff1b;VM&#xff1a;视图模型&#xff08;ViewModel&#xff09;Vue的实例对象。 Vue.js…

WSDM2022推荐系统相关论文整理(一)

2022年第15届国际网络搜索与数据挖掘会议WSDM在2022年2月21日到25日于线上举行&#xff0c;共收到了786份有效投稿&#xff0c;最终录取篇数为159篇&#xff0c;录取率为20.23%。作为主流的搜索与数据挖掘会议&#xff0c;论文的话题主要侧重于搜索、推荐以及数据挖掘领域&…

第二证券炒股知识:北交所的股票是a股吗?是主板吗?

北交所的股票是a股&#xff0c;但不属于主板&#xff0c;是一个单独的板块。 A股主板是在上海证券买卖所或许深圳证券买卖所上市的公司&#xff0c;主板通常是大盘股&#xff0c;多为商场占有率高、规划大、盈余安稳良好的大型企业。沪市主板以600、601或603最初&#xff0c;深…

Leetcode 654:最大二叉树

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums 构建的 最大二叉树…

(学习笔记)数据基建-数据安全

&#xff08;学习笔记&#xff09;数据基建-数据安全 数据安全数据安全实施难点数据安全保障流程数据安全措施实施阶段数据安全如何量化产出数据安全思考 数据安全 数据安全问题是最近比较热的话题&#xff0c;数据泄漏引发的用户信任危机事件也比比皆是&#xff0c;以及跨部门…

2024年度计划

1&#xff0c;人工智能学习路径&#xff1a; Python基础&#xff1a;深兰科技机器学习&#xff1a;马士兵教育计算机视觉和图像处理&#xff1a;黑马程序员NLP自然语言处理&#xff1a;黑马程序员计算机视觉与图像处理项目&#xff1a;智慧交通&#xff1a;实时人脸识别检测&am…

什么是负载均衡?在网络中如何实现?

负载均衡&#xff08;Load Balancing&#xff09;是一种网络技术&#xff0c;用于将网络请求或数据传输任务分发到多个服务器或处理单元上&#xff0c;以实现更高效的资源利用、更高的处理能力和更好的系统可靠性。负载均衡的目标是优化资源使用、最大化吞吐量、减少响应时间&a…