spring防止重复点击,两种注解实现(AOP)
第一种:@EasyLock
简介
为了简化可复用注解,自己实现的注解,代码简单随拿随用
使用方式
1.创建一个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EasyLock {long waitTime() default 1;long leaseTime() default 3;
}
2. 创建一个AOP切面类(异常可以自定义,这里我用的Cicada)
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
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.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import vip.lspace.agent.common.annotation.EasyLock;
import vip.lspace.agent.common.exception.LockException;import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;@Component
@Aspect
@Slf4j
public class LockAop {@Resourceprivate LockException lockException;@ResourceRedissonClient redissonClient;private static final String redisLockKeyParamName = "redisLockKey";@Pointcut("@annotation(vip.lspace.agent.common.annotation.EasyLock)")public void lockPointcut() {}@Around("lockPointcut()")public Object doAround(ProceedingJoinPoint proceedingJoinPoint) {log.info("EasyLock locking");MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();EasyLock easyLock = methodSignature.getMethod().getAnnotation(EasyLock.class);Object[] args = proceedingJoinPoint.getArgs();String[] parameterNames = methodSignature.getParameterNames();String redisLockKey = "";for (int i = 0; i < parameterNames.length; i++) {if (parameterNames[i].equals(redisLockKeyParamName)) {redisLockKey = (String) args[i];}}if (StringUtils.isBlank(redisLockKey)) {throw lockException.lockKeyNotExist();}RLock lock = redissonClient.getLock(redisLockKey);try {if (!lock.tryLock(easyLock.waitTime(), easyLock.leaseTime(), TimeUnit.SECONDS)) {throw lockException.getLockTimeOut(redisLockKey);}return proceedingJoinPoint.proceed();} catch (Throwable e) {throw new RuntimeException(e);} finally {if (lock.isLocked() && lock.isHeldByCurrentThread()) {lock.unlock();log.info("当前线程{},释放锁:{}", Thread.currentThread().getId(), redisLockKey);}}}
@CicadaBean(namespace = "lock")
public interface LockException {@ExceptionInfo(errCode = 13001, errMessage = "没找到分布式锁key")CicadaException lockKeyNotExist();@ExceptionInfo(errCode = 13002, errMessage = "超时未获取到锁: %s")CicadaException getLockTimeOut(String key);
}
3.使用方式
注意点:
必须包含名为redisLockKey的参数,作为redis的key
@Override@EasyLock(waitTime = 1,leaseTime = 3)@Transactional(rollbackFor = Exception.class)public void concurrentTest(String redisLockKey) {PaymentBillBacktrack paymentBillBacktrack = paymentBillBacktrackService.getById(1L);String refundRequestNo = paymentBillBacktrack.getMerchantRefundRequestNo();paymentBillBacktrack.setMerchantRefundRequestNo(String.valueOf(Integer.parseInt(refundRequestNo) + 1));paymentBillBacktrackService.updateById(paymentBillBacktrack);}
第二种:@NiceLock
简介
大佬提供的公共组件,引包后可直接使用,使用简单,细节代码可看nicelock: nicelock:一个注解,即可使用Java的分布式锁。(基于Redisson)
使用方式
1.引包
一定得引入1.1.6的,甚至最新版本,不然有问题!!!
<dependency><groupId>com.suchtool</groupId><artifactId>nicelock-spring-boot-starter</artifactId><version>1.1.6</version>
</dependency>
2.使用
@Override@Transactional@NiceLock(keys = {"#userId"},acquireTimeout = 3000L,exception = NiceLockLockFailException.class,message = "服务已完成评价,不能重复提交")public void test(String userId) {System.out.println("修改订单: 用户ID=" + userId);}
注解中传入了exception参数后,报错会输出message的内容,更加直观
测试方式
Apifox中的自动化测试中可以配多个线程同时执行接口,测试重复点击是否生效
相关文章:
spring防止重复点击,两种注解实现(AOP)
第一种:EasyLock 简介 为了简化可复用注解,自己实现的注解,代码简单随拿随用 使用方式 1.创建一个注解 Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) Documented public interface EasyLock {long waitTime() default …...
Spring Boot 3 实现 MySQL 主从数据库之间的数据同步
✅ Spring Boot 3 实现 MySQL 主从数据库之间的数据同步 在实际项目中,为了提高 系统的读性能 和 数据的可用性,通常会使用 主从数据库架构。Spring Boot 提供了对 多数据源 的良好支持,可以轻松配置 主从数据库 的数据同步,实现 读写分离。 🎯 方案介绍 我们将通过 Sp…...
WPS-JS宏快速上手
WPS JS宏注意事项 代码后面可以不写分号“ ; ”; 缩进对程序的运行影响不大,但为了易读(防止自己以后看不懂),还是乖乖写好; 代码是逐行运行的,意味着下面一行代码错了,前面的代码…...
力扣hot100——堆
215. 数组中的第K个最大元素 快速排序 class Solution { public:int findKthLargest(vector<int>& a, int k) {auto qsort [&](this auto&& qsort, int l, int r) -> void {if (l r) return;int i l - 1, j r 1;int x a[(l r) / 2];/*如果把…...
【小制作】米家模拟手指点击
代码功能解释 这段代码是一个基于Arduino平台的控制程序,主要功能包括: 初始化:设置引脚模式、初始化编码器、舵机和EEPROM。按键检测:处理按钮的单击、双击和长按事件,并根据事件执行相应操作。编码器更新ÿ…...
ubuntu1604 apt镜像源切换
1、如何查看当前源 cat /etc/apt/sources.list less /etc/apt/sources.list 2、apt源修改为阿里镜像,这里ubuntu是1604: deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/…...
leetcode刷题笔记
题目思路1.两数之和哈希表2.两数相加链表操作3. 无重复字符的最长子串滑动窗口,特别注意数组越界情况!4. 寻找两个正序数组的中位数5.最长回文子串从中间向两边扩展,注意整个字符串都是回文串的边界情况10.正则表达式匹配动态规划,…...
修复 ITunes 在 Windows 或 Mac 上不断崩溃的问题 [100% 有效]
对于 iDevice 用户来说,只能通过 iTunes 在 iDevice 和计算机之间传输文件的困境一直是一个紧迫的问题。所有 iPhone 用户可能都知道,iTunes 并不是一款高效的应用程序,有时性能会很差,例如在 iDevices 和计算机之间传输文件时不断…...
Mac M2基于MySQL 8.4.3搭建(伪)主从集群
前置准备工作 安装MySQL 8.4.3 参考博主之前的文档,在本地Mac安装好MySQL:Mac M2 Pro安装MySQL 8.4.3安装目录:/usr/local/mysql,安装好的MySQL都处于运行状态,需要先停止MySQL服务最快的方式:系统设置 …...
Visual Point Cloud Forecasting enables Scalable Autonomous Driving——点云论文阅读(12)
此内容是论文总结,重点看思路!! 文章概述 这篇文章介绍了一个名为 ViDAR 的视觉点云预测框架,它通过预测历史视觉输入生成未来点云,作为自动驾驶的预训练任务。ViDAR 集成了语义、三维几何和时间动态信息,有效提升了感知、预测和规划等自动驾驶核心任务的性能。实验表明…...
handpose x plus 数据解析 >> DataBall
DataBall 助力快速掌握数据集的信息和使用方式,会员享有 百种数据集,持续增加中。 需要更多数据资源和技术解决方案,知识星球: “DataBall - X 数据球(free)” ---------------------------- 样品数据: 通过加入知识…...
LINUX线程操作
文章目录 线程的定义LINUX中的线程模型一对一模型多对一模型多对多模型 线程实现原理线程的状态新建状态(New)就绪状态(Runnable)运行状态(Running)阻塞状态(Blocked)死亡状态&#…...
每日一学——日志管理工具(ELK Stack)
5.1 ELK Stack 5.1.1 Elasticsearch索引机制 嘿,小伙伴们!今天我们要聊聊ELK Stack——一套由Elasticsearch、Logstash和Kibana组成的强大日志管理工具集。通过这套工具,我们可以轻松地收集、存储、搜索和可视化日志数据。首先,…...
设计模式 结构型 适配器模式(Adapter Pattern)与 常见技术框架应用 解析
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个类的接口转换成客户端所期望的另一个接口,从而使原本因接口不兼容而无法一起工作的类能够协同工作。这种设计模式在软件开发中非常有用,尤其是在需要集成…...
【Leetcode】732. 我的日程安排表 III
文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接🔗 当 k k k 个日程存在一些非空交集时(即, k k k 个日程包含了一些相同时间),就会产生 k k k 次预订。 给你一些日程安排 [startTime, endTime…...
Flutter Android修改应用名称、应用图片、应用启动画面
修改应用名称 打开Android Studio,打开对应项目的android文件。 选择app下面的manifests->AndroidManifest.xml文件,将android:label"bluetoothdemo2"中的bluetoothdemo2改成自己想要的名称。重新启动或者重新打包,应用的名称…...
RocketMQ消费者如何消费消息以及ack
1.前言 此文章是在儒猿课程中的学习笔记,感兴趣的想看原来的课程可以去咨询儒猿课堂 这篇文章紧挨着上一篇博客来进行编写,有些不清楚的可以看下上一篇博客: https://blog.csdn.net/u013127325/article/details/144934073 2.broker是如何…...
华为消费级QLC SSD来了
近日,有关消息显示,华为的消费级SSD产品线,eKitStor Xtreme 200E系列,在韩国一家在线零售商处首次公开销售,引起了业界的广泛关注。 尽管华为已经涉足服务器级别的SSD制造多年,但直到今年6月才正式推出面向…...
Conda 安装 Jupyter Notebook
文章目录 1. 安装 Conda下载与安装步骤: 2. 创建虚拟环境3. 安装 Jupyter Notebook4. 启动 Jupyter Notebook5. 安装扩展功能(可选)6. 更新与维护7. 总结 Jupyter Notebook 是一款非常流行的交互式开发工具,尤其适合数据科学、机器…...
高等数学学习笔记 ☞ 极限的运算法则与存在准则
1. 极限的运算法则 (1)有限个无穷小的和是无穷小。 (2)有限个无穷小的乘积是无穷小。 备注: ①:无限个无穷小的和不一定是无穷小,反例如下…...
【开源】创建自动签到系统—QD框架
1. 介绍 QD是一个 基于 HAR 编辑器和 Tornado 服务端的 HTTP 定时任务自动执行 Web 框架。 主要通过抓包获取到HAR来制作任务模板,从而实现异步响应和发起HTTP请求 2. 需要环境 2.1 硬件需求 CPU:至少1核 内存:推荐 ≥ 1G 硬盘:推…...
k8s集群,CRI-Docker部署条件及方法
CRI-Docker部署条件及方法 文章目录 CRI-Docker部署条件及方法CRI-Docker使用条件安装 cri-docker 的步骤: CRI-Docker使用条件 在 Kubernetes 1.20 及以上版本,kubeadm 默认使用 containerd 作为容器运行时(Container Runtime Interface, C…...
STLG_01_09_程序设计C语言 - 指针
C语言中的指针是一个非常重要的概念,它允许程序直接访问和操作内存地址。理解指针对于掌握C语言编程至关重要。 1. 指针的基本概念 指针:指针是一个变量,它存储的是另一个变量的内存地址。指针变量:指针变量专门用来存储内存地址…...
Seaborn的分类柱状图sns.barplot()
Seaborn的分类柱状图sns.barplot 一、sns.barplot()参数详解二、代码实现一、sns.barplot()参数详解 sns.barplot 是 Seaborn 库中用于绘制分类柱状图(bar chart)的函数。Seaborn 是一个基于 Matplotlib 的数据可视化库,它提供了更高级别的接口来绘制统计图形,并且有更…...
SpringBoot入门之创建一个Hello World项目
文章目录 一、创建一个SpringBoot项目二、配置pom.xml文件三、下载Maven依赖四、创建一个Controller类:com.devops.controller.HelloController五、创建一个引导类:com.devops.HelloApplication六、启动项目七、访问8080八、完整项目结构九、参考视频 一…...
MAC系统QT Creator的快捷键
安装好QT Creator后使用了一段时间,真是越用越难受,只想说🗑️。。。 找一圈qt creator的快捷键 0. 快捷键界面 这里的搜索真的是…无语,不考虑是人查找吗?? 1. 代码前后浏览 2. 移动代码 3. 半自动导入…...
qml Rectangle详解
1、概述 Rectangle是Qt Quick中的一个基础图形元素,用于在QML界面上绘制一个可带边框和可填充的矩形区域。它继承自Item类,因此具有Item的所有属性和功能,如位置、尺寸、变换等。通过Rectangle,可以创建各种矩形形状,…...
C语言中关于数据类型带来的陷阱
前言 笔者在阅读《深入理解计算机系统》时,理解了为何C语言被称为不安全语言,C语言除了指针非常灵活可能会导致大量漏洞之外,C语言的无符号数据也可能带来致命性危害。 扩展一个数据的表示 将一个无符号数转换为更大的数据类型,…...
设计心得——流程图和数据流图绘制
一、流程图和数据流图 在软件开发中,画流程图和数据流图可以说是几乎每个人都会遇到。 1、数据流(程)图 Data Flow Diagram,DFG。它可以称为数据流图或数据流程图。其主要用来描述系统中数据流程的一种图形工具,可以将…...
【AimRT】AimRT Hello World
目录 一、工程结构二、源码说明/CMakeLists.txt/cmake/GetAimRT.cmake/src/CMakeLists.txt/src/module/helloworld_module/CMakeLists.txt/src/app/helloworld_app/CMakeLists.txt/src/install/cfg/helloworld_cfg.yaml/src/module/helloworld_module/helloworld_module.h/src/…...
在Typora中实现自动编号
文章目录 在Typora中实现自动编号1. 引言2. 准备工作3. 自动编号的实现3.1 文章大纲自动编号3.2 主题目录(TOC)自动编号3.3 文章内容自动编号3.4 完整代码 4. 应用自定义CSS5. 结论 在Typora中实现自动编号 1. 引言 Typora是一款非常流行的Markdown编辑…...
Vue2/Vue3使用DataV
Vue2 注意vue2与3安装DataV命令命令是不同的Vue3 DataV - Vue3 官网地址 注意vue2与3安装DataV命令命令是不同的 vue3vite 与 Vue3webpack 对应安装也不同vue3vite npm install kjgl77/datav-vue3全局引入 // main.ts中全局引入 import { createApp } from vue import Da…...
Docker 环境中搭建 Redis 哨兵模式集群的步骤与问题解决
在 Docker 环境中搭建 Redis 哨兵模式集群的步骤与问题解决 在 Redis 高可用架构中,哨兵模式(Sentinel)是确保 Redis 集群在出现故障时自动切换主节点的一种机制。通过使用 Redis 哨兵,我们可以实现 Redis 集群的监控、故障检测和…...
数据库设计
数据库设计全攻略:从理论到实践 在当今数字化驱动的世界里,数据已然成为企业和组织最为宝贵的资产之一。而数据库,作为数据的“栖息地”,其设计的优劣直接关系到整个信息系统的性能、可维护性以及能否高效满足业务需求。一个精心构思的数据库设计方案,就如同为一座高楼打…...
三甲医院等级评审八维数据分析应用(一)--组织、制度、管理可视化篇
一、引言 1.1 研究背景与意义 在当今医疗领域,三甲医院作为医疗服务的核心载体,肩负着保障民众健康、推动医学进步的重任。随着信息技术的飞速发展,数据已成为医院运营管理、医疗质量提升以及科学决策的关键要素。三甲医院等级评审作为衡量医院综合实力与服务水平的重要标…...
【2025软考高级架构师】案例题重点知识——第一部分
1.架构风格相关问题 什么是架构风格? 软件架构风格类似于建筑风格,从相同类型的软件系统中抽取其架构的共性,是一种惯用模式,反映了众多系统共有的结构和语义 (1)软件架构为软件系统提供了一个结构、行为和属性的高级抽象。 (2)软件架构风格是特定应用领域的惯用模式,架…...
Science Robotics让软机器人“活”得更久的3D打印!
软机器人硬件在医疗、探索无结构环境等领域有广泛应用,但其生命周期有限,导致资源浪费和可持续性差。软机器人结合软硬组件,复杂组装和拆卸流程使其难以维修和升级。因此,如何延长软机器人的生命周期并提高其可持续性成为亟待解决…...
【JVM】总结篇-运行时内存篇
文章目录 JVM内存模型(内存结构)程序计数器 pc虚拟机栈本地方法栈 native堆堆空间堆中一些JVM参数堆中垃圾回收过程MinorGC MajorGC FullGC年轻代GC(Minor GC)触发机制:老年代GC(Major GC/Full GC)触发机制:…...
【2025最新计算机毕业设计】基于SpringBoot+Vue智慧养老医护系统(高质量源码,提供文档,免费部署到本地)【提供源码+答辩PPT+文档+项目部署】
作者简介:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容:🌟Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…...
【数据仓库】hive on Tez配置
hive on Tez 搭建 前提是hive4.0hadoop3.2.2数仓已搭建完成,现在只是更换其执行引擎 为Tez。搭建可参考【数据仓库】hive hadoop数仓搭建实践文章。 Tez 下载 下载地址 https://archive.apache.org/dist/tez/ 官网地址 https://tez.apache.org/releases/apac…...
基于HTML和CSS的旅游小程序
一、技术基础 HTML(HyperText Markup Language):超文本标记语言,用于定义网页的内容和结构。在旅游小程序中,HTML用于搭建页面的基本框架,包括标题、段落、图片、链接等元素,以及用于交互的表单…...
CDP集成Hudi实战-文件存储布局实况讲解
[〇]关于本文 本文我们参考一张在hdfs中的hud表讲解一下hudi表的文件存储布局 [一]时间线文件解析 目录结构中列出的文件和子目录如下: 1-文件类型解析 时间线目录中的文件主要有以下几种类型: <commit_id>.deltacommit.inflight 表示一项事务&…...
22408操作系统期末速成/复习(考研0基础上手)
第一部分:计算题: 考察范围:(标红的是重点考) 第一章:CPU利用率: 第二章: 进程调度算法(需要注意不同调度算法的优先级和题目中给出的是否可以抢占【分为可抢占和不可抢占ÿ…...
Qt的信号与槽
文章目录 信号与槽机制信号与槽的定义 Qt使用信号与槽机制进行对象间的通信。当某个对象的状态发生变化时,该对象会触发一个信号。 该信号和另外一些对象的槽函数绑定,信号的触发将导致这些槽函数的执行,以处理第一个对象状态的变化。触发信号…...
牛客网刷题 ——C语言初阶——JZ15 二进制中1的个数
1.题目描述 题目OJ链接 描述 输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。 2.思路 求2进制中1的个数,可以转换为求每一位,1的个数,1&1还是1 所以判断如果该数值&1为真,我们就co…...
【游戏设计原理】47 - 超游戏思维
对于这条原理,我首先想到的是开放世界,或者探索性游戏,这是最能包容各类玩家的游戏类型。这类游戏定义了基本规则,玩家的可操作性很强。就像上图里的沙池一样,里面有滑梯,是规则性比较明确的,而…...
Elasticsearch Serverless中的数据流自动分片深度解析
Elasticsearch Serverless中的数据流自动分片深度解析 一、Elasticsearch Serverless概述 1. 什么是Elasticsearch Serverless Elasticsearch Serverless是一种云端全托管的Elasticsearch服务,它基于云原生Serverless技术架构,提供自动弹性和完全免运…...
Elasticsearch JavaRestClient版
文章目录 初始化RestHighLeveClient(必要条件)索引库操作1.创建索引库(4步)2.删除索引库(3步)3.判断索引库是否存在(3步)4.总结:四步走 文档操作1.创建文档(4…...
通过爬虫方式实现视频号助手发布视频
1、将真实的cookie贴到解压后目录中cookie.txt文件里,修改python代码里的user_agent和video_path, cover_path等变量的值,最后运行python脚本即可; 2、运行之前根据import提示安装一些常见依赖,比如requests等; 3、2025年1月份最新版; 代码如下: import json import…...
如何在VMware ESXi和Workstation中打开VMDK文件?
VMware 中的 VMDK 是什么? 在 VMware 中,VMDK 是虚拟磁盘文件的格式,全称是 Virtual Machine Disk。VMDK 文件用于存储虚拟机的硬盘内容,包括操作系统、应用程序、文件等。它相当于虚拟机的硬盘驱动器,可以模拟出各种…...