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-…

零知识证明友好的波塞冬哈希(ZK-friendly Hashing: Poseidon)

文章目录 背景什么是 Poseidon 哈希技术原理各STARK friendly hash函数性能对比SHA256 VS Pedersen参考背景 2018年7月2日,以太坊基金会给StarkWare团队2年的赞助,用于寻找新的STARK friendly hash (SFH) 函数,可用于在区块链中构建transparent且抗量子安全的proof系统。 …

从遍历到A星寻路

在游戏当中&#xff0c;经常需要找一个点到其它点的路径。在之前的一篇博文(地图编辑器开发&#xff08;三&#xff09;)中也有使用到到A寻路。我们期望能找到最短的路径&#xff0c;同时也需要考虑到查找路径的时间消耗。游戏中的地图可以图的数据结构来表示&#xff0c;然后使…

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

【重点】【滑动窗口】239. 滑动窗口最大值

题目 也可参考&#xff1a;剑指offer——面试题65&#xff1a;滑动窗口的最大值 class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int[] res new int[nums.length - k 1];Deque<Integer> q new LinkedList<>();int inx 0;while (inx <…

.locked、locked1勒索病毒的最新威胁:如何恢复您的数据?

导言&#xff1a; 网络安全问题变得愈加严峻。.locked、locked1勒索病毒是近期备受关注的一种恶意软件&#xff0c;给用户的数据带来了巨大威胁。本文将深入探讨.locked、locked1勒索病毒的特征&#xff0c;探讨如何有效恢复被其加密的数据&#xff0c;并提供一些建议&#xf…

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

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

代码随想录算法训练营第三十一天|435. 无重叠区间 , 763.划分字母区间 , 56. 合并区间

435. 无重叠区间 - 力扣&#xff08;LeetCode&#xff09; 给定一个区间的集合 intervals &#xff0c;其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量&#xff0c;使剩余区间互不重叠 。 示例 1: 输入: intervals [[1,2],[2,3],[3,4],[1,3]] 输出: 1 解…

C语言 操作符详解

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

Linux下~目录和home目录的区别

在 Linux 中&#xff0c;~&#xff08;波浪号&#xff09;路径和 home 路径都与用户的主目录&#xff08;home directory&#xff09;相关。 ~&#xff08;波浪号&#xff09;路径&#xff1a;表示当前登录用户的主目录。例如&#xff0c;如果你当前是以用户user1的身份登陆&am…

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;而系统如何判定权…

关于typename与using typedef的使用归纳

关于typename与using/typedef的使用归纳 typename 其实对于typename.在以前的编程中并没有typename这个关键字的&#xff0c;在以前我们写模板时&#xff0c;使用的 都是class这个关键字 template <class T> void swap(T& x, T& y) {int temp;temp x;x y;y…