Redis 分布式锁测试

一、前提依赖(除去SpringBoot项目基本依赖外):

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId>
</dependency><!-- 配置使用redis启动器 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><!-- 引入阿里fastjson2依赖 -->
<dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.42</version>
</dependency><!--junit 测试-->
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version>
</dependency>

二、我这里用到的实体类(Orderinfo ):

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
public class Orderinfo implements Serializable {private String onum;private Integer eid;private BigDecimal price;private String fromname;private String fromaddress;private String fromtel;private String toname;private String toaddress;private String totel;private String fromcardnum;private Integer state;private Date createtime;private static final long serialVersionUID = 1L;public String getOnum() {return onum;}public void setOnum(String onum) {this.onum = onum == null ? null : onum.trim();}public Integer getEid() {return eid;}public void setEid(Integer eid) {this.eid = eid;}public BigDecimal getPrice() {return price;}public void setPrice(BigDecimal price) {this.price = price;}public String getFromname() {return fromname;}public void setFromname(String fromname) {this.fromname = fromname == null ? null : fromname.trim();}public String getFromaddress() {return fromaddress;}public void setFromaddress(String fromaddress) {this.fromaddress = fromaddress == null ? null : fromaddress.trim();}public String getFromtel() {return fromtel;}public void setFromtel(String fromtel) {this.fromtel = fromtel == null ? null : fromtel.trim();}public String getToname() {return toname;}public void setToname(String toname) {this.toname = toname == null ? null : toname.trim();}public String getToaddress() {return toaddress;}public void setToaddress(String toaddress) {this.toaddress = toaddress == null ? null : toaddress.trim();}public String getTotel() {return totel;}public void setTotel(String totel) {this.totel = totel == null ? null : totel.trim();}public String getFromcardnum() {return fromcardnum;}public void setFromcardnum(String fromcardnum) {this.fromcardnum = fromcardnum == null ? null : fromcardnum.trim();}public Integer getState() {return state;}public void setState(Integer state) {this.state = state;}public Date getCreatetime() {return createtime;}public void setCreatetime(Date createtime) {this.createtime = createtime;}
}

三、场景-抢单

        1. 添加RedisLockUtil:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@Component
public class RedisLockUtil {@Autowiredprivate RedisTemplate<String, String> redisTemplate;/*** 加锁* @param key   键* @param value 当前时间 + 超时时间* @return 是否拿到锁*/public boolean lock(String key, String value) {if (redisTemplate.opsForValue().setIfAbsent(key, value)) {return true;}String currentValue = redisTemplate.opsForValue().get(key);//如果锁过期if (!StringUtils.isEmpty(currentValue)&& Long.parseLong(currentValue) < System.currentTimeMillis()) {
//设置新值,返回旧值String oldValue = redisTemplate.opsForValue().getAndSet(key, value);//是否已被别人抢占 比对currentValue 和oldValue 是否一致 确保未被其他人抢占return !StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue);}return false;}/*** 解锁** @param key   键* @param value 当前时间 + 超时时间*/public void unlock(String key, String value) {try {String currentValue = redisTemplate.opsForValue().get(key);if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {redisTemplate.opsForValue().getOperations().delete(key);}} catch (Exception e) {System.out.println("redis解锁异常");}}
}

        2. 新建RedisLockTest类: 

import com.alibaba.fastjson2.JSON;
import com.logistics.order.entity.Orderinfo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
@Controller
public class RedisLockTest {@Autowiredpublic StringRedisTemplate stringRedisTemplate;@Autowiredpublic RedisLockUtil redisLock;//模拟入库@Testpublic void insertRedis(){Orderinfo orderInfo1 = new Orderinfo();orderInfo1.setOnum("1");orderInfo1.setEid(1);Orderinfo orderInfo2 = new Orderinfo();orderInfo2.setOnum("2");orderInfo2.setEid(2);Orderinfo orderInfo3 = new Orderinfo();orderInfo3.setOnum("3");orderInfo3.setEid(3);List<Orderinfo> orderinfoList = new ArrayList<Orderinfo>();orderinfoList.add(orderInfo1);orderinfoList.add(orderInfo2);orderinfoList.add(orderInfo3);orderinfoList.forEach(x -> {stringRedisTemplate.boundHashOps("order").put(x.getOnum(), JSON.toJSONString(x));});System.out.println("入库成功。");}//压测@GetMapping("/getOrder")public void getOrder(String onum){//定义redis锁的keyString lockkey = "orderkey";//定义锁的超时时间 1sLong ex = 1000L;String valueTimeout = System.currentTimeMillis()+ex+"";//判断锁是否加成功boolean lock = redisLock.lock(lockkey, valueTimeout);if(lock){String orderJson = (String)stringRedisTemplate.boundHashOps("order").get(onum);Orderinfo order = JSON.parseObject(orderJson, Orderinfo.class);System.out.println("订单:"+order.getOnum() +" 被抢到。");stringRedisTemplate.boundHashOps("order").delete(onum);//释放锁redisLock.unlock(lockkey,valueTimeout);}}
}

        3. 进入 Redis 的可视化客户端工具内查看添加信息:

        4. 模拟抢单:

@GetMapping("/getOrder")public void getOrder(String onum){//定义redis锁的keyString lockkey = "orderkey";//定义锁的超时时间 1sLong ex = 1000L;String valueTimeout = System.currentTimeMillis()+ex+"";//判断锁是否加成功boolean lock = redisLock.lock(lockkey, valueTimeout);if(lock){String orderJson = (String)stringRedisTemplate.boundHashOps("order").get(onum);Orderinfo order = JSON.parseObject(orderJson, Orderinfo.class);System.out.println("订单:"+order.getOnum() +" 被抢到。");stringRedisTemplate.boundHashOps("order").delete(onum);//释放锁redisLock.unlock(lockkey,valueTimeout);}}

四、Jmeter压测:

        1. 创建线程组:

        2. 添加 HTTP 请求:

        3. 给一个 Linstener 监听的结果树:

        4. 模拟每秒 50 个请求:

        5. 设置请求及请求参数:

        6. 点击 5 图中的绿色小三角启动压测:

        Idea控制台:

Redis分布式锁:

分布式锁,是一种思想,它的实现方式有很多。比如,我们将沙滩当做分布式锁的组件,那么它看起来应该是这样的:

加锁

在沙滩上踩一脚,留下自己的脚印,就对应了加锁操作。其他进程或者线程,看到沙滩上已经有脚印,证明锁已被别人持有,则等待。

解锁

把脚印从沙滩上抹去,就是解锁的过程。

锁超时

为了避免死锁,我们可以设置一阵风,在单位时间后刮起,将脚印自动抹去。

分布式锁的实现有很多,比如基于数据库、memcached、Redis、系统文件、zookeeper等。它们的核心的理念跟上面的过程大致相同。

在这里我们通过单节点Redis实现一个简单的分布式锁。

1、加锁

加锁实际上就是在redis中,给Key键设置一个值,如果设置值成功,则表示客户端获得了锁。

2、解锁

解锁的过程就是将Key键删除

Redis分布式锁实现原理:

利用redis在同一时刻操作一个键的值只能有一个进程的特性,如果能设值成功就获取到锁。解锁,就是删除指定的键。为防止死锁可以设置锁超时时间,如果锁超时就释放锁。

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

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

相关文章

【React设计】React企业级设计模式

Image Source : https://bugfender.com React是一个强大的JavaScript库&#xff0c;用于构建用户界面。其基于组件的体系结构和构建可重用组件的能力使其成为许多企业级应用程序的首选。然而&#xff0c;随着应用程序的规模和复杂性的增长&#xff0c;维护和扩展变得更加困难。…

计算机辅助药物设计AIDD-小分子-蛋白质|分子生成|蛋白质配体相互作用预测

文章目录 计算机辅助药物设计AIDD【小分子专题】AIDD概述及药物综合数据库学习机器学习辅助药物设计图神经网络辅助药物设计自然语言处理辅助药物设计药物设计与分子生成 计算机辅助药物设计【蛋白质专题】蛋白质数据结构激酶-Kinase相似性学习基于序列的蛋白质属性预测基于结构…

SSM项目实战-前端-添加分页控件-调正页面布局

1、Index.vue <template><div class"common-layout"><el-container><el-header><el-row><el-col :span"24"><el-button type"primary" plain click"toAdd">新增</el-button></el-…

JavaScript新特性

JavaScript新特性 紧接上文&#xff0c;JS入门手册&#x1f4af; 这篇文章介绍了&#xff0c;JavaScript的基本语法&#xff0c;而随着时代发展&#xff0c;JS早已今非昔比&#xff0c;推荐一个大佬的文章&#xff1a;阮一峰老师 ECMAScript ECMAScript&#xff08;简称“E…

锂电池包膜机通过设备管理系统做好预测性维护的作用

在现代工业生产中&#xff0c;包膜机在锂电产业链中处于电池制造环节&#xff0c;是锂电池生产线上的关键设备之一。然而&#xff0c;随着生产规模的扩大和工作环境的复杂化&#xff0c;锂电池包膜机也面临着常见故障和维护需求。为了更好地管理和维护锂电池包膜机&#xff0c;…

新加坡社区领袖卓顺发的荣誉与大爱精神

2023年11月24日,善济医社义务执行主席卓顺发太平绅士JP, BBM(L), PVPA受邀出席内政部主办的答谢活动2023,主宾为内政部长兼律政部长尚穆根先生(Mr. K Shanmugam)。 2018年起,卓顺发受委为太平绅士后,应内政部邀请,担任纪律咨询委员会委员和巡狱太平绅士及视察团委员。他在颁奖…

Java并发模式和设计策略

引言 小伙伴们&#xff0c;今天小黑要和咱们聊聊Java并发编程的那些事儿。在现代软件开发中&#xff0c;高效地处理多任务是一个不可或缺的能力。特别是对于服务成千上万用户的应用&#xff0c;能够同时处理多个操作不仅是一个加分项&#xff0c;简直是必备技能了&#xff01;…

【openssl】RSA 生成公钥私钥 |通过私钥获取公钥

通过博客&#xff1a;Window系统如何编译openssl 编译出openssl.exe&#xff08;位于apps文件夹下&#xff09;。 现在需要使用它获得公钥私钥、通过私钥获取公钥 目录 说明&#xff01;&#xff01;&#xff01; 一.定位openssl.exe目录 二、进入命令cmd 三、生成私钥 …

IDEA 下载mysql驱动下载在不下来

结合一下 https://www.cnblogs.com/dadian/p/11936056.htmlhttps://www.cnblogs.com/dadian/p/11936056.html并且下载的 在idea改名 加入 加入到库 等待一会就要你输入sql的root和密码了,就OK

冰酒为什么贵?一篇给你讲清楚

冰酒因为昂贵被定义为&#xff1a;颜色和价格都如同黄金的奢侈品。那么&#xff0c;号称液体黄金的冰酒为什么这么贵呢&#xff1f;云仓酒庄给大家讲讲清楚。 云仓酒庄多品牌多代言运营模式&#xff0c;邀请当红明星来出席或代言自身产品&#xff0c;找到与品牌自身形象、调性相…

C语言 操作符详解

C语言学习 目录 文章目录 前言 一、算术操作符 二、移位操作符 2.1 左移操作符 2.2 右移操作符 三、位操作符 3.1 按位与操作符 & 3.2 按位或操作符 | 3.3 按位异或操作符 ^ 四、赋值操作符 五、单目操作符 5.1 逻辑反操作符&#xff01; 5.2 正值、负值-操作符 5.3 取地址…

vscode中使用luaide-lite插件断点调试cocos2dx-lua

使用quick-cocos2dx-lua&#xff0c;用了众多插件&#xff0c;包括免费的BabeLua,VS调试太慢&#xff0c;vscode上的免费的EmmyLua, 还有收费的luaide&#xff0c;都没搞出来&#xff0c;唯独这个免费luaide-lite用成功了&#xff0c;步骤也简单&#xff0c;可以断点调试&#…

Linux(14):进程管理

一个程序被加载到内存当中运作&#xff0c;那么在内存内的那个数据就被称为进程(process)。 进程是操作系统上非常重要的概念&#xff0c;所有系统上面跑的数据都会以进程的型态存在。 进程 在 Linux底下所有的指令与能够进行的动作都与权限有关&#xff0c;而系统如何判定权…

JDK 历史版本下载以及指定版本应用

参考&#xff1a; 官网下载JAVA的JDK11版本&#xff08;下载、安装、配置环境变量&#xff09;_java11下载-CSDN博客 Gradle&#xff1a;执行命令时指定 JDK 版本 - 微酷网 下载 打开官网地址 Java Downloads | Oracle 当前版本在这里&#xff0c;但是我们要下载历史版本 选…

vue3 + TS 项目中使用pinia-plugin-persistedstate持久化缓存

Vue 3和Pinia是一对非常好的组合&#xff0c;可以帮助你构建现代化的Vue应用程序。而pinia-plugin-persistedstate是一个用于在Pinia存储中实现状态持久化的插件。下面我将详细介绍如何在Vue 3应用程序中使用Pinia和pinia-plugin-persistedstate模块。 首先&#xff0c;确保你…

[C++]priority_queue的介绍及模拟实现

目录 priority_queue的介绍及模拟实现&#xff1a;&#xff1a; priority_queue的介绍 priority_queue的定义方式 priority_queue各个接口的使用 堆的向上调整算法 堆的向下调整算法 仿函数 priority_queue的模拟实现 反向迭代器的底层原理 反向迭代器的模拟实现 priority_que…

SWD和JTAG

1、调试接口概念 1&#xff09;SWD&#xff1a;Serial Wire Debug&#xff0c;代表串行线调试&#xff0c;是ARM设计的协议&#xff0c;用于对其微控制器进行编程和调试。 SWD 引脚&#xff1a; SWDIO–串行数据线&#xff0c;用于数据的读出和写入SWDCLK–串行时钟线&#…

前端开发_CSS

CSS定义 层叠样式表 (Cascading Style Sheets&#xff0c;缩写为 CSS&#xff09;&#xff0c;是一种 样式表 语言&#xff0c;用来描述 HTML 文档的呈现&#xff08;美化内容&#xff09; 书写位置&#xff1a;title 标签下方添加 style 双标签&#xff0c;style 标签里面书…

内外网转换NAT

目录 分类 内核参数配置文件 SNAT 网关服务器配置 配置内网主机 配置外网主机 配置SNAT 内网主机测试 DNAT 配置网关服务器 支持的规则链&#xff1a;INPUT、OUTPUT、PREROUTING、POSTROUTING 分类 SNAT&#xff08;将外网设备共享给内网&#xff09; source NAT &a…

关于rocketMQ踩坑的那些事

在最近&#xff0c;我所写的这个项目需要使用到rocketMQ&#xff0c;为了图方便我便使用的是Windows版本的&#xff0c;但是在使用的过程中首先是发现无法发送消息出去&#xff0c;报错信息为 org.apache.rocketmq.client.exception.MQClientException: Send [3] times, still …