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

基于Redisson实现分布式锁

基于redisson实现分布式锁

之前背过分布式锁几种实现方案的八股文,但是并没有真正自己实操过。现在对AOP有了更深一点的理解,就自己来实现一遍。

1、分布式锁的基础知识

分布式锁是相对于普通的锁的。普通的锁在具体的方法层面去锁,单体应用情况下,各个进入的请求都只能进入到一个应用里面,也就能达到锁住方法的效果。
而分布式的系统,将一个项目部署了多个实例,通过nginx去做请求转发将请求分到各个实例。不同实例之间共用代码,共用数据库这些。比如一个请求进入A实例,获得了锁;如果继续有请求进入A实例,则会排队等待。但如果请求进入的是B实例呢?B实例的锁和A实例没有关系,那么进入B实例的请求也会获取到锁,然后进入方法。这样锁的作用就没有达到。这种情况下,就引出了分布式锁,这是专门为了解决分布式系统的并发问题的。做法是让不同的实例都能使用同一个锁。比如redis,redis内部是单线程的,把锁放在redis,这样就可以多个实例共用一个锁。

2、Redisson

Redisson是架设在Redis基础上的一个Java驻内存数据网格(In-Memory Data Grid)。充分的利用了Redis键值数据库提供的一系列优势,基于Java实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。
利用Redisson可以很轻松就实现分布式锁。

3、实现的几个点

如何动态将拼接key所需的参数值传入到切面?
有两种方案,一种是通过给参数加上注解来标识那些参数是作为key使用的。在切面内通过获取方法的参数上的注解来获取所需的参数值。
另一种是通过定义key的参数名,在切面获取方法参数的参数名进行对比,一样的就是所需的参数。
获取锁失败如何重试?
Redisson提供了重试的能力,以及重试等待时长等。

4、代码实现

前置操作:项目引入Redis

引入Redisson依赖

        <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.13.6</version></dependency>

项目yaml文件

spring:#reids配置redis:database: 1host: 127.0.0.1port: 6379# redisson配置redisson:# 数据库编号database: 1# 节点地址address: redis://127.0.0.1:6379

编写Redisson配置文件

package com.yumoxuan.myapp.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {@Value("${spring.redis.redisson.address}")public String address;@Value("${spring.redis.redisson.database}")public Integer database;@Beanpublic RedissonClient getRedissonClient(){Config config=new Config();config.useSingleServer().setAddress(address).setDatabase(database);return Redisson.create(config);}
}

定义分布式锁注解

package com.yumoxuan.myapp.core.aspect.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributedLock {/*** 锁的名称* @return*/String name() default "";/*** 锁的参数key* @return*/String[] key() default {};/*** 锁过期时间* @return*/int expireTime() default 30;/*** 锁过期时间单位* @return*/TimeUnit timeUnit() default TimeUnit.SECONDS;/*** 等待获取锁超时时间* @return*/int waitTime() default 10;
}

切面实现

package com.yumoxuan.myapp.core.aspect;
import com.yumoxuan.myapp.core.aspect.annotation.DistributedLock;
import lombok.extern.slf4j.Slf4j;
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 javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
@Slf4j
@Aspect
@Component
public class DistributedLockAspect {@Resourcepublic RedissonClient redissonClient;@Pointcut("@annotation(com.yumoxuan.myapp.core.aspect.annotation.DistributedLock)")public void pointcut() {}@Around("pointcut()")public Object around(ProceedingJoinPoint point) throws Throwable {MethodSignature signature = (MethodSignature) point.getSignature();Method method = signature.getMethod();DistributedLock annotation = method.getAnnotation(DistributedLock.class);String name = annotation.name();String key = name;String[] keys = annotation.key();int expireTime = annotation.expireTime();TimeUnit timeUnit = annotation.timeUnit();int waitTime = annotation.waitTime();Object[] args = point.getArgs(); // 参数值String[] paramNames = signature.getParameterNames(); // 参数名for (int i = 0; i < args.length; i++) {String paramName = paramNames[i];for (int j = 0; j < keys.length; j++) {if (paramName.equals(keys[j])) {key = key + ":" + args[i];}}}log.info(Thread.currentThread().getId()+" "+"key:"+key);RLock lock = redissonClient.getLock(key);boolean res = false;Object obj = null;try {if (waitTime == -1) {res = true;lock.lock(expireTime, timeUnit);} else {res = lock.tryLock(waitTime, expireTime, timeUnit);}if (res) {obj = point.proceed();} else {log.error("分布式锁获取异常");}} finally {//释放锁if (res) {lock.unlock();}}return obj;}
}

验证效果

	@ApiOperation(value="my_app_user-添加", notes="my_app_user-添加")@PostMapping(value = "/add")@DistributedLock(name = "添加分布式锁",key = {"userId"})public Result<?> add(@RequestBody MyAppUser myAppUser, String userId) {log.info(Thread.currentThread().getId()+" "+new Date());try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}return Result.ok();}

如下图,76.77的key是一样的,从打印的时间上看,两次打印时间相差了5秒,说明后者被阻塞。而68的线程key和另外两个不一样,所以没有被阻塞,在76和77的中间就运行了。符合分布式锁的效果。
在这里插入图片描述

5、拓展

要实现一个功能完善的分布式锁,其实还有很多内容。
比如锁要过期了,但事务未执行完毕,则需要进行锁续期,这个可以通过守护线程实现。

相关文章:

基于Redisson实现分布式锁

基于redisson实现分布式锁 之前背过分布式锁几种实现方案的八股文&#xff0c;但是并没有真正自己实操过。现在对AOP有了更深一点的理解&#xff0c;就自己来实现一遍。 1、分布式锁的基础知识 分布式锁是相对于普通的锁的。普通的锁在具体的方法层面去锁&#xff0c;单体应…...

Android Studio下载Gradle特别慢,甚至超时,失败。。。解决方法

使用Android studio下载或更新gradle时超级慢怎么办&#xff1f; 切换服务器&#xff0c;立马解决。打开gradle配置文件 修改服务器路径 distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-7.3.3-bin.zip 最后&#xff0c;同步&#xff0c;下载&#xff0c;速…...

leetcode--二叉树中的最长交错路径

leetcode地址&#xff1a;二叉树中的最长交错路径 给你一棵以 root 为根的二叉树&#xff0c;二叉树中的交错路径定义如下&#xff1a; 选择二叉树中 任意 节点和一个方向&#xff08;左或者右&#xff09;。 如果前进方向为右&#xff0c;那么移动到当前节点的的右子节点&…...

c++ primer plus 第15章友,异常和其他:15.1.3 其他友元关系

c primer plus 第15章友&#xff0c;异常和其他&#xff1a;15.1.3 其他友元关系 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 15.1.3 其他友元关系 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可…...

uniapp+vue3页面跳转和传参

页面跳转&#xff1a; uni.navigateTo({url: /pages/index}) 返回上一层&#xff1a; uni.navigateBack ({delta: 1 }) 页面跳转时传参&#xff1a; 跳转前的页面&#xff1a; uni.navigateTo({url: "/pages/index?id123"}) 跳转后的页面&#xff1a; onLoa…...

硬链接和软链接

在Linux系统中&#xff0c;链接&#xff08;Link&#xff09;是一种特殊的文件&#xff0c;它指向另一个文件或目录。链接分为两种类型&#xff1a;硬链接&#xff08;Hard Link&#xff09;和软链接&#xff08;也称为符号链接&#xff0c;Symbolic Link&#xff09;。 1. 硬…...

属性描述符初探——Vue实现数据劫持的基础

目录 属性描述符——Vue实现数据劫持的基础 一、属性描述符是什么&#xff1f; ​编辑 1.1、属性描述符示例 1.2、用属性描述符定义属性及获取对象的属性描述符 1.3、带有读取器和设置器的属性描述符 二、使用属性描述符的情景 2.1、封装和数据隐藏 使用getter和setter…...

字节也没余粮了?天底下没有永远免费的GPT-4;AI产品用订阅制就不合理!让用户掏钱的N种定价技巧嘿嘿 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;ShowMeAI官网 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; 1. 当 Coze 也开始收费&#xff1a;天底下没有「永远」免费的 GPT-4 注&#xff1a;这里 Coze 指海外版。国内版 扣子 还是免费。 Coze (海外版) 官网链接 → htt…...

【Matlab 路径优化】基于蚁群算法的XX市旅游景点线路优化系统

基于蚁群算法的XX市旅游景点线路优化系统 &#xff08;一&#xff09;客户需求&#xff1a; ①考虑旅游景点的空间分布、游客偏好等因素&#xff0c;实现了旅游线路的智能规划 ②游客选择一景点出发经过所要游览的所有景点只一次&#xff0c;最后回到出发点的前提下&#xf…...

我关于Excel使用点滴的笔记

本篇笔记是我关于Excel使用点滴的学习笔记&#xff0c;摘要和地址链接列表。临时暂挂&#xff0c;后面可能在不需要时删除。 (笔记模板由python脚本于2024年06月28日 12:23:32创建&#xff0c;本篇笔记适合初通Python&#xff0c;熟悉六大基本数据(str字符串、int整型、float浮…...

【Java安装】windows10+JDK21+IDEA

文章目录 一、JDK安装1. 下载完成后按照自己需要的位置安装2. 配置环境变量2.1 JAVA_HOME变量2.2 PATH配置 3. 验证4. helloworld 二、IDEA安装三、IDEA-HelloWorld 一、JDK安装 JDK安装链接 1. 下载完成后按照自己需要的位置安装 2. 配置环境变量 2.1 JAVA_HOME变量 安装…...

《简历宝典》01 - 一文带你学会如何写一份糟糕透顶的简历

我们每个人几乎都会面对找工作这件事&#xff0c;而找工作或者说求职首先就是要写一份简历。今天狗哥将以一个不同的视角带你写一份无与伦比&#xff0c;糟糕透顶的求职简历&#xff0c;说实话&#xff0c;其实几年前&#xff0c;我就是这么写的。 目录 1. 文件名 2. 基本信…...

多链路聚合通信路由在应急救援活动中的重要性及解决方案

在应急救援指挥活动中&#xff0c;多链路聚合通信设备如同一座坚固的桥梁&#xff0c;将信息快速、准确地传递至每一个角落。面对复杂多变的救援现场&#xff0c;这类设备展现了其卓越的适应性和稳定性。 想象一下&#xff0c;当灾害突然降临&#xff0c;信息的传递变得至关重…...

PyCharm中如何将某个文件设置为默认运行文件

之前在使用JetBrain公司的另一款软件IDEA的时候&#xff0c;如果在选中static main函数后按键altenter可以默认以后运行Main类的main函数。最近在使用PyCharm学习Python&#xff0c;既然同为一家公司的产品而且二者的风格如此之像&#xff0c;所以我怀疑PyCharm中肯定也有类似的…...

【杂交版】植物大战僵尸杂交版v2.1最新版本下载链接

B站游戏作者潜艇伟伟迷于6月13日中午更新了植物大战僵尸杂交版2.1版本&#xff0c;有老版本的也可以完美继承存档数据。 不多废话下载链接放上&#xff1a; 夸克网盘链接&#xff1a;https://pan.quark.cn/s/095de551d1d1 UC网盘链接&#xff1a;https://drive.uc.cn/s/86debb3…...

图像增强及运算篇之图像掩膜直方图和HS直方图

一.图像掩膜直方图 如果要统计图像的某一部分直方图&#xff0c;就需要使用掩码&#xff08;蒙板&#xff09;来进行计算。假设将要统计的部分设置为白色&#xff0c;其余部分设置为黑色&#xff0c;然后使用该掩膜进行直方图绘制&#xff0c;其完整代码如下所示。 # -*- codi…...

Python商务数据分析知识专栏(六)——Python数据分析的应用④Python数据分析实训

Python商务数据分析知识专栏&#xff08;六&#xff09;——Python数据分析的应用④Python数据分析实训 Python数据分析实训一.iris数据处理实训1.1 拓展学习资料&Python环境介绍1.2 读取数据&修改列名称1.3 以PythonConsole方式执行代码1.4 缺失值处理1.5 重置索引 二…...

【Python机器学习】处理文本数据——将文本数据表示为词袋

用于机器学习的文本有一种最简单的方法&#xff0c;也是最有效且最常用的方法&#xff0c;就是使用词袋表示。使用这种表示方法时&#xff0c;我们舍弃了输入文本中的大部分结构&#xff0c;比如章节、段落、句子和格式&#xff0c;只计算语料库中&#xff0c;只计算语料库中每…...

论文写作全攻略:Kimi辅助下的高效学术写作技巧

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 完成论文写作是一个多阶段的过程&#xff0c;涉及到不同的任务和技能。以下是按不同分类总结的向Kimi提问的prompt&#xff0c;以帮助你在论文写作过程中取得成功&#xff1a; 1. 选题与…...

通证经济重塑经济格局

在数字化转型的全球浪潮中&#xff0c;通证经济模式犹如一股新兴力量&#xff0c;以其独特的价值传递与共享机制&#xff0c;重塑着经济格局&#xff0c;引领我们步入数字经济的新纪元。 通证&#xff0c;作为这一模式的核心&#xff0c;不仅是权利与权益的数字化凭证&#xf…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...