【分布式锁】Redission实现分布式锁
接着上一节,我们遇到了超卖的问题,并通过Redis实现分布式锁,进行了解决。本节 我将换一种方式实现分布式锁。
前提:
nginx、redis、nacos
模块1:
provider-and-consumer 端口 8023
模块2
rabbitmq-consumer 端口 8021
添加依赖
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.15.6</version>
</dependency>
业务代码
模块1代码 RedisTestController.java
package com.atguigu.gulimall.providerconsumer.controller;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.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.UUID;
import java.util.concurrent.TimeUnit;/*** @author: jd* @create: 2024-07-08*/
@RestController
@RequestMapping("/test")
@Slf4j
public class RedisTestController {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Autowiredprivate RedissonClient redissonClient;@GetMapping("/RedissonLock")public String deductStockByRedisson(){//写死一个固定商品ID,作为我们被秒杀的商品String lockKey="lock:product:102";//获取锁对象RLock lock = redissonClient.getLock(lockKey);//加锁,使用lock方法,锁将会自动续命lock.lock();try{//获取当前库存String stock1 = stringRedisTemplate.opsForValue().get("stock");if(stock1==null){System.out.println("秒杀未开始,请等开始后操作下单");return "end";}int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));if(stock>0){// 扣减库存int realStock = stock - 1;// 更新库存stringRedisTemplate.opsForValue().set("stock", realStock + "");System.out.println("扣减成功,剩余的库存为:" + realStock);}else {System.out.println("扣减库存失败,库存不足");}}finally {if(lock.isLocked()&&lock.isHeldByCurrentThread()){//释放分布式锁lock.unlock();System.out.println("分布式锁释放"); //解锁}}return "end";}}
模块2代码 RedisTestController.java
package com.atguigu.gulimall.rabbitmqconsumer.controller;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.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.UUID;
import java.util.concurrent.TimeUnit;/**** 和provider-and-consumer 这两个服务中都有这个RedisTestController,用来模拟两个不同的服务* @author: jd* @create: 2024-07-08*/
@RestController
@RequestMapping("/test")
@Slf4j
public class RedisTestController {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Autowiredprivate RedissonClient redissonClient;@GetMapping("/RedissonLock")public String deductStockByRedisson(){//写死一个固定商品ID,作为我们被秒杀的商品String lockKey="lock:product:102";//获取锁对象RLock lock = redissonClient.getLock(lockKey);//加锁,使用lock方法,锁将会自动续命lock.lock();try{//获取当前库存String stock1 = stringRedisTemplate.opsForValue().get("stock");if(stock1==null){System.out.println("秒杀未开始,请等开始后操作下单");return "end";}int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));if(stock>0){// 扣减库存int realStock = stock - 1;// 更新库存stringRedisTemplate.opsForValue().set("stock", realStock + "");System.out.println("扣减成功,剩余的库存为:" + realStock);}else {System.out.println("扣减库存失败,库存不足");}}finally {if(lock.isLocked()&&lock.isHeldByCurrentThread()){//释放分布式锁lock.unlock();System.out.println("分布式锁释放"); //解锁}}return "end";}}
测试结果:
单次请求,我发送两次,结果:


第二次:

成功扣减。
并发情况模拟:
当前库存数

压测:

并发压测结果:
8023模块
扣减成功,剩余的库存为:83
分布式锁释放
扣减成功,剩余的库存为:81
分布式锁释放
扣减成功,剩余的库存为:80
分布式锁释放
扣减成功,剩余的库存为:78
分布式锁释放
扣减成功,剩余的库存为:76
分布式锁释放
扣减成功,剩余的库存为:75
分布式锁释放
扣减成功,剩余的库存为:72
分布式锁释放
扣减成功,剩余的库存为:68
分布式锁释放
扣减成功,剩余的库存为:66
分布式锁释放
扣减成功,剩余的库存为:64
分布式锁释放
扣减成功,剩余的库存为:62
分布式锁释放
扣减成功,剩余的库存为:60
分布式锁释放
扣减成功,剩余的库存为:58
分布式锁释放
扣减成功,剩余的库存为:56
分布式锁释放
扣减成功,剩余的库存为:54
分布式锁释放
扣减成功,剩余的库存为:52
分布式锁释放
扣减成功,剩余的库存为:50
分布式锁释放
扣减成功,剩余的库存为:48
分布式锁释放
扣减成功,剩余的库存为:46
分布式锁释放
扣减成功,剩余的库存为:44
分布式锁释放
扣减成功,剩余的库存为:42
分布式锁释放
扣减成功,剩余的库存为:40
分布式锁释放
扣减成功,剩余的库存为:38
分布式锁释放
扣减成功,剩余的库存为:36
分布式锁释放
扣减成功,剩余的库存为:34
分布式锁释放
扣减成功,剩余的库存为:32
分布式锁释放
扣减成功,剩余的库存为:30
分布式锁释放
扣减成功,剩余的库存为:28
分布式锁释放
扣减成功,剩余的库存为:26
分布式锁释放
扣减成功,剩余的库存为:24
分布式锁释放
扣减成功,剩余的库存为:22
分布式锁释放
扣减成功,剩余的库存为:20
分布式锁释放
扣减成功,剩余的库存为:18
分布式锁释放
扣减成功,剩余的库存为:16
分布式锁释放
扣减成功,剩余的库存为:14
分布式锁释放
扣减成功,剩余的库存为:12
分布式锁释放
扣减成功,剩余的库存为:10
分布式锁释放
扣减成功,剩余的库存为:8
分布式锁释放
扣减成功,剩余的库存为:6
分布式锁释放
扣减成功,剩余的库存为:4
分布式锁释放
扣减成功,剩余的库存为:2
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
8021模块日志
扣减成功,剩余的库存为:82
分布式锁释放
扣减成功,剩余的库存为:79
分布式锁释放
扣减成功,剩余的库存为:77
分布式锁释放
扣减成功,剩余的库存为:74
分布式锁释放
扣减成功,剩余的库存为:73
分布式锁释放
扣减成功,剩余的库存为:71
分布式锁释放
扣减成功,剩余的库存为:70
分布式锁释放
扣减成功,剩余的库存为:69
分布式锁释放
扣减成功,剩余的库存为:67
分布式锁释放
扣减成功,剩余的库存为:65
分布式锁释放
扣减成功,剩余的库存为:63
分布式锁释放
扣减成功,剩余的库存为:61
分布式锁释放
扣减成功,剩余的库存为:59
分布式锁释放
扣减成功,剩余的库存为:57
分布式锁释放
扣减成功,剩余的库存为:55
分布式锁释放
扣减成功,剩余的库存为:53
分布式锁释放
扣减成功,剩余的库存为:51
分布式锁释放
扣减成功,剩余的库存为:49
分布式锁释放
扣减成功,剩余的库存为:47
分布式锁释放
扣减成功,剩余的库存为:45
分布式锁释放
扣减成功,剩余的库存为:43
分布式锁释放
扣减成功,剩余的库存为:41
分布式锁释放
扣减成功,剩余的库存为:39
分布式锁释放
扣减成功,剩余的库存为:37
分布式锁释放
扣减成功,剩余的库存为:35
分布式锁释放
扣减成功,剩余的库存为:33
分布式锁释放
扣减成功,剩余的库存为:31
分布式锁释放
扣减成功,剩余的库存为:29
分布式锁释放
扣减成功,剩余的库存为:27
分布式锁释放
扣减成功,剩余的库存为:25
分布式锁释放
扣减成功,剩余的库存为:23
分布式锁释放
扣减成功,剩余的库存为:21
分布式锁释放
扣减成功,剩余的库存为:19
分布式锁释放
扣减成功,剩余的库存为:17
分布式锁释放
扣减成功,剩余的库存为:15
分布式锁释放
扣减成功,剩余的库存为:13
分布式锁释放
扣减成功,剩余的库存为:11
分布式锁释放
扣减成功,剩余的库存为:9
分布式锁释放
扣减成功,剩余的库存为:7
分布式锁释放
扣减成功,剩余的库存为:5
分布式锁释放
扣减成功,剩余的库存为:3
分布式锁释放
扣减成功,剩余的库存为:1
分布式锁释放
扣减成功,剩余的库存为:0
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
扣减库存失败,库存不足
分布式锁释放
可以看到,没有超卖现象。至此Redission实现分布式锁已经OK。
redis实现分布式锁 可见博文:【分布式锁】Redis实现分布式锁
相关文章:
【分布式锁】Redission实现分布式锁
接着上一节,我们遇到了超卖的问题,并通过Redis实现分布式锁,进行了解决。本节 我将换一种方式实现分布式锁。 前提: nginx、redis、nacos 模块1: provider-and-consumer 端口 8023 模块2 rabbitmq-consumer 端口 8021 …...
UE4/5 对话系统
参考教程:UE4甜筒教艺术生学蓝图#21.UE4对话系统(1)--唠嗑案例展示_哔哩哔哩_bilibili 说来惭愧两年前看的教程,现在才记录一下,很好的教程推荐大家观看 1.首先创建两个枚举,内容如下 2.创建三个结构体,内容如下 3.再…...
Golang | Leetcode Golang题解之第275题H指数II
题目: 题解: func hIndex(citations []int) int {n : len(citations)return n - sort.Search(n, func(x int) bool { return citations[x] > n-x }) }...
Python—面向过程编程,详细讲解(类和实例,初始化函数,类中封装数据与操作)
1.类和实例 类:类别 实例(对象):类型塑造出来的某一个具体的内容 isinstance(对象,类) 返回一个对象是否是一个类的实例 # 声明一个整数类的实例10 a int(10) # a 10 print(type(a), isinstance(a, int)) a flo…...
Linux云计算 |【第一阶段】SERVICES-DAY2
主要内容: DNS服务基础及搭建、特殊解析(针对地址库文件:DNS轮询 DNS泛域名解析 DNS别名)、缓存DNS(全局转发forwarders)、DNS递归迭代(子域授权)、DNS主从架构搭建、DNS主从数据同步 一、DNS工…...
el-upload照片墙自定义上传多张图片(手动一次性上传多张图片)包含图片回显,删除
需求:el-upload照片墙自定义上传多张图片(手动一次性上传多张图片)包含图片回显,删除,预览,在网上看了很多,都没有说怎么把数据转为file格式的,找了很久最终实现, 难点&a…...
三星Unpacked发布会即将举行:有新款折叠屏手机,还有智能戒指
随着7月的脚步渐近,科技界的目光再次聚焦于三星,它即将在法国巴黎举办今年的第二场Unpacked发布会。这不仅是一场新品的展示,更是三星对创新科技的一次深刻诠释。 从Galaxy Z Fold 6的全新设计,到Galaxy Z Flip 6的显著升级&…...
【Python】Matplotlib简要教程
文章目录 一、简介二、一些基本概念2.1 图表元素2.2 常见图表类型2.3 主要绘图函数及其返回值2.4 Artists 的概念 三、基本图表详解3.1 成对数据3.11 折线图:plot()🟨设置图表样式🟨设置各种标签🟨设置坐标轴🟨绘制子图…...
数驭未来,景联文科技构建高质大模型数据库
国内应用层面的需求推动AI产业的加速发展。根据IDC数据预测,预计2026年中国人工智能软件及应用市场规模会达到211亿美元。 数据、算法、算力是AI发展的驱动力,其中数据是AI发展的基石,中国的数据规模增长速度预期将领跑全球。 2024年《政府工…...
视频汇聚平台EasyCVR启动出现报错“cannot open shared object file”的原因排查与解决
安防视频监控EasyCVR安防监控视频系统采用先进的网络传输技术,支持高清视频的接入和传输,能够满足大规模、高并发的远程监控需求。EasyCVR平台支持多种视频流的外部分发,如RTMP、RTSP、HTTP-FLV、WebSocket-FLV、HLS、WebRTC、fmp4等…...
VMware 安装完,设备管理器中没有虚拟网卡(vmnet0、wmnet1、vmnet8) / 虚拟网络编辑器中没有桥接模式
问题:VMware 安装完,设备管理器中没有虚拟网卡(vmnet0、wmnet1、vmnet8) / 虚拟网络编辑器中没有桥接模式 1、确认 Device Install Service 和 Device Setup Manager 没有被禁用 Device Install Service 和 Device Setup Manager是 Windows 操作系统中…...
构建高效Node.js中间层:探索请求合并转发的艺术
🎉 博客主页:【剑九 六千里-CSDN博客】 🎨 上一篇文章:【CSS盒模型:掌握网页布局的核心】 🎠 系列专栏:【面试题-八股系列】 💖 感谢大家点赞👍收藏⭐评论✍ 引言&#x…...
中断和EXIT原理介绍
中断和EXIT原理介绍 一、中断的介绍?二、EXIT的介绍1.EXIT作用2.EXIT的详情3.EXIT中AFIO复用的作用4.STM32中AFIO复用作用 一、中断的介绍? 二、EXIT的介绍 EXTI(Extern Interrupt)外部中断 1.EXIT作用 EXTI可以监测指定GPIO口…...
vcpkg或者命令行需要设置代理时如何设置
当使用命令行或者vcpkg时,有时候需要设置代理来下载一些代码,那么可以这样: 本地先起一个http或者socks5的代理服务器。监听127.0.0.1:10808如果本地是http代理服务器,在命令行执行: set http_proxyhttp://127.0.0.1:…...
tensorflow安装及数据操作----学习笔记(一)
安装Miniconda 下载对应系统版本的Miniconda。我的系统是ubuntu,所以选择Miniconda3 Linux 64-bit。下载后执行下载的sh脚本 sh Miniconda3-latest-Linux-x86_64.sh -b执行后,运行conda初始化命令 ~/miniconda3/bin/conda init关闭当前命令终端&#…...
顺序表和单链表的经典算法题
目录 前言 一、基础思想(数组) 1. 移除元素 2.删除有序元素的重复项 3.合并两个有序数组 二、单链表算法 1.移除链表元素 2.翻转链表 3.合并两个有序的链表 前言 Hello,小伙伴们,今天我们来做一个往期知识的回顾,今天我将…...
python基础知识点(蓝桥杯python科目个人复习计划71)
做些简单题 第一题:确定字符串是否包含唯一字符 题目描述: 实现一个算法来识别一个字符串的字符是否是唯一的。 若唯一输出YES,否则输出NO。 输入描述: 输入一个字符串,长度不超过100. 输出描述; 输出一行&…...
【大数据专题】Flink题库
1 . 简述什么是Apache Flink ? Apache Flink 是一个开源的基于流的有状态计算框架。它是分布式地执行的,具备低延迟、高吞吐的优秀性能,并且非常擅长处理有状态的复杂计算逻辑场景 2 . 简述Flink 的核心概念 ? Flink 的核心概念…...
Python鲁汶意外莱顿复杂图拓扑分解算法
🎯要点 🎯算法池化和最佳分区搜索:🖊网格搜索 | 🖊发现算法池 | 🖊返回指定图的最佳划分 | 🖊返回指定图的最佳分区 | 🎯适应度和聚类比较功能:🖊图的划分 |…...
【C++】类和对象之继承
目录 继承的概念和定义 继承的概念 继承的定义 继承的定义格式 继承关系和访问限定符 继承基类成员访问方式的变化 访问权限实例 基类和派生类对象赋值转换 继承中的作用域 派生类的默认成员函数 继承与友元 继承与静态成员 复杂的菱形继承及菱形虚拟继承 继承的…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
