Redis 分布式锁测试

news2024/11/17 15:58:10

一、前提依赖(除去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 {
   @Autowired
   private 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 {
    @Autowired
    public StringRedisTemplate stringRedisTemplate;

    @Autowired
    public RedisLockUtil redisLock;

    //模拟入库
    @Test
    public 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锁的key
        String lockkey = "orderkey";

        //定义锁的超时时间 1s
        Long 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锁的key
        String lockkey = "orderkey";
        //定义锁的超时时间 1s
        Long 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.coloradmin.cn/o/1283674.html

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

相关文章

进入软件的世界

选择计算机 上高中的时候&#xff0c;因为沉迷于网络游戏&#xff0c;于是对计算机产生了浓厚的兴趣&#xff0c;但是那个时候对于计算机的了解还是非常肤浅的。上大学的时候&#xff0c;也就义无反顾的选择了计算机专业&#xff0c;其实并不是一个纯粹的计算机专业&#xff0…

代码随想录算法训练营第五十五天【动态规划part15】 | 392.判断子序列、115.不同的子序列

392.判断子序列 题目链接 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 求解思路 也可以用双指针来做。 动规五部曲 1.确定dp数组及其下标含义 以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的字符串t&#xff0c;相同子序列的长度…

Mybatis中的设计模式

Mybatis中的设计模式 Mybatis中使用了大量的设计模式。 以下列举一些看源码时&#xff0c;觉得还不错的用法&#xff1a; 创建型模式 工厂方法模式 DataSourceFactory 通过不同的子类工厂&#xff0c;实例化不同的DataSource TransactionFactory 通过不同的工厂&#xff…

【雷电模拟器桥接问题解决方法】

1.ROOT权限开启 2.开启网络桥接模式&#xff0c;选择静态IP设置&#xff0c;点击安装桥接网卡&#xff0c;填写IP地址&#xff08;注意&#xff1a;IP地址要与host主机在同一IP段内&#xff09; 3.重启后 adb shell就能进入到模拟器控制台中了&#xff0c;如果出现以下内容&…

记一次若依二开的简单流程

记一次若依二开的简单流程 前言: 搞Java后端的应该都知道若依框架&#xff0c;是一个十分强大且功能齐全的开源的快速开发平台&#xff0c;且毫无保留给个人及企业免费使用。很多中小型公司会直接在该系统上进行二次开发使用。本文记录一次使用若依二开零编码的简单实现&#…

JFrog----软件的SBOM分析简介

文章目录 什么是SBOM&#xff1f;SBOM分析的重要性SBOM分析的过程结语 什么是SBOM&#xff1f; SBOM&#xff0c;全称是“软件物料清单”&#xff0c;它像是一个详尽的清单&#xff0c;列出了构成特定软件的所有组件&#xff0c;包括库、模块、包等。这就像是制造业中的物料清…

iOS ------ UICollectionView

一&#xff0c;UICollectionView的简介 UICollectionView是iOS6之后引入的一个新的UI控件&#xff0c;它和UITableView有着诸多的相似之处&#xff0c;其中许多代理方法都十分类似。简单来说&#xff0c;UICollectionView是比UITbleView更加强大的一个UI控件&#xff0c;有如下…

C语言中如何取一串比特中的特定位的比特

#include <iostream> #include <bitset> using namespace std; /* 向右的移位操作相当于丢掉最后的几位&#xff0c;然后剩下的位数进行“与”运算即可。 */ int main() {int a 0x2FB7; //0x2FB70010 1111 1011 0111char end3 (a >> 4) & 0x07; //取a…

Javaweb之Vue路由的详细解析

5 Vue路由 5.1 路由介绍 将资代码/vue-project(路由)/vue-project/src/views/tlias/DeptView.vue拷贝到我们当前EmpView.vue同级&#xff0c;其结构如下&#xff1a; 此时我们希望基于4.4案例中的功能&#xff0c;实现点击侧边栏的部门管理&#xff0c;显示部门管理的信息&am…

“影响力”经济:抖音为什么更值得商家、达人长期深耕?

文&#xff5c;新熔财经 作者&#xff5c;叶一城 数亿的活跃用户&#xff0c;简单而自然的切入方式&#xff0c;快速、高频的执行效率&#xff0c;让抖音对电商界的冲击无可阻挡。 这背后&#xff0c;流量玩法登峰造极&#xff0c;是很多人的直接观感。 但实际上&#xff0…

FL Studio 21.2.1.3859中文破解版及FL Studio怎么录制

FL Studio 21.2.1.3859中文破解版是一个数字音频工作站 (DAW)。该软件借助各种编辑工具、插件和效果&#xff0c;让您可以录制、混音和掌握高度复杂的音乐作品。FL Studio 21还允许您注册和编辑 MIDI 文件&#xff0c;您可以在众多可用乐器之一上演奏这些文件。FL Studio 拥有 …

【VRTK】【VR开发】【Unity】10-连续移动

课程配套学习资源下载 https://download.csdn.net/download/weixin_41697242/88485426?spm=1001.2014.3001.5503 【概述】 连续移动与瞬移有如下不同: 连续移动不容易打断沉浸对于新手或者不适应者来说更容易晕动 我对玩家的建议:连续移动前后左右可以用摇杆,转向用自己…

java常用知识点记忆

类的继承与多态 类的继承不支持多重继承非private 方法才可以被覆盖覆盖的方法要求&#xff0c;子类中的方法的名字&#xff0c;参数列表&#xff0c;返回类型与父类相同方法的重载是在一个类中定义方法名字相同&#xff0c;但是参数列表不同的方法要是在子类中定义了与父类名字…

Huawei FusionSphere FusionCompte FusionManager

什么是FusionSphere FusionSphere 解决方案不独立发布软件&#xff0c;由各配套部件发布&#xff0c;请参 《FusionSphere_V100R005C10U1_版本配套表_01》。 目前我们主要讨论FusionManager和FusionCompute两个组件。 什么是FusionCompte FusionCompute是华为提供的虚拟化软…

深度学习训练 tricks(持续更新)

妈妈&#xff0c;我的炼丹炉子炸啦&#xff08;不是&#xff09; 妈妈&#xff0c;我的深度学习模型训练好了&#xff01; 本文持续更新&#xff0c;如果有什么你知道的深度学习模型训练技巧&#xff0c;可以在评论区提出&#xff0c;我会加进来的。 文章目录 weight decaywe…

3DMM模型

目录 BFMBFM_200901_MorphableModel.matexp_pca.bintopology_info.npyexp_info.npy BFM BFM_2009 01_MorphableModel.mat from scipy.io import loadmat original_BFM loadmat("01_MorphableModel.mat") # dict_keys: [__header__, __version__, __globals__, # …

C++ 文件操作之配置文件读取

C 文件操作之配置文件读取 在项目应用时常常会涉及一些调参工作&#xff0c;如果项目封装成了.exe或者.dll&#xff0c;那么频繁调参多次编译是一件十分低效的事情&#xff0c;如果代码算法或者逻辑是一定的&#xff0c;那么参数完全可以通过读入配置文件来获取之前在用C - op…

SpringBoot药品进销存管理系统(诊所管理系统)(乡村药店管理系统)

SSM毕设分享 SpringBoot药品进销存管理系统(诊所管理系统)(乡村药店管理系统) 1 项目简介 Hi&#xff0c;各位同学好&#xff0c;这里是郑师兄&#xff01; 今天向大家分享一个毕业设计项目作品【SpringBoot药品进销存管理系统(诊所管理系统)(乡村药店管理系统)】 师兄根据实…

ROS-ROS通信机制-话题通信

文章目录 一、话题通信基础知识二、话题通信基本操作2-1 C2-2 Python2-3 C与python节点通信 三、自定义msg3-1 自定义msg3-2 C实现自定义msg调用3-3 Python实现自定义msg调用 一、话题通信基础知识 话题通信实现模型是比较复杂的&#xff0c;该模型如下图所示,该模型中涉及到三…

zxjy001-项目整体介绍

1、项目类型 全栈项目 前端&#xff1a;系统后台&#xff0c;系统前台后端&#xff1a;提供API接口 2、项目技术栈 前端 Vue,Element,Axios,NodeJs后端 Spring Boot,Spring Cloud,MybatisPlus,Spring Security,Redis,Maven,JWT,OAuth2其他技术 阿里云oss服务阿里云视频点播…