2、基于redis实现分布式锁

目录

    • 2.1. 基本实现
    • ==2.2. 防死锁==
    • ==2.3. 防误删==
    • 2.4. redis中的lua脚本
      • 2.4.1 redis 并不能保证
      • 2.4.2 lua介绍
    • 2.5. 使用lua保证删除原子性

2.1. 基本实现

借助于redis中的命令setnx(key, value),key不存在就新增,存在就什么都不做。同时有多个客户端发送setnx命令,只有一个客户端可以成功,返回1(true);其他的客户端返回0(false)。
在这里插入图片描述

  1. 多个客户端同时获取锁(setnx)
  2. 获取成功,执行业务逻辑,执行完成释放锁(del)
  3. 其他客户端等待重试

改造StockService方法:

 /*** redis setnx实现分布式锁,最基本的哪一种 !!!*/public void deduct() {// 加锁setnxBoolean lock = this.redisTemplate.opsForValue().setIfAbsent("lock", "111");if (!lock) {// 没有获取到锁,进行重试!!try {Thread.sleep(50);this.deduct();} catch (InterruptedException e) {e.printStackTrace();}} else {try {// 1. 查询库存信息String stockStr = redisTemplate.opsForValue().get("stock:" + "1001");// 2. 判断库存是否充足if (stockStr != null && stockStr.length() != 0) {Long stock = Long.parseLong(stockStr);if (stock > 0) {redisTemplate.opsForValue().set("stock:" + "1001", String.valueOf(stock - 1));}}} finally {// 解锁this.redisTemplate.delete("lock");}}}

使用 jmeter 进行压测
在这里插入图片描述
查看库存数量
在这里插入图片描述

上述代码优化,不断重试的过程中一直进行递归,最终导致栈的溢出。

解决

/***  while循环代替递归,解决不断重试可能导致的栈溢出的问题*/public void deduct() {// 加锁setnxwhile (this.redisTemplate.opsForValue().setIfAbsent("lock1", "1")) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}try {// 1. 查询库存信息String stockStr = redisTemplate.opsForValue().get("stock:" + "1001");// 2. 判断库存是否充足if (stockStr != null && stockStr.length() != 0) {Long stock = Long.parseLong(stockStr);if (stock > 0) {redisTemplate.opsForValue().set("stock:" + "1001", String.valueOf(stock - 1));}}} finally {// 解锁this.redisTemplate.delete("lock1");}}}

2.2. 防死锁

问题:setnx刚刚获取到锁,当前服务器宕机,导致del释放锁无法执行,进而导致锁无法锁无法释放(死锁)
解决:给锁设置过期时间,自动释放锁。

设置过期时间两种方式:

  • 通过expire设置过期时间(缺乏原子性:如果在setnx和expire之间出现异常,锁也无法释放)
  • 使用set指令设置过期时间:set key value ex 3 nx(既达到setnx的效果,又设置了过期时间)

在这里插入图片描述

2.3. 防误删

持有锁的线程在锁的内部出现了阻塞,导致他的锁自动释放,这时其他线程,线程2来尝试获得锁,就拿到了这把锁,然后线程2在持有锁执行过程中,线程1反应过来,继续执行,而线程1执行过程中,走到了删除锁逻辑,此时就会把本应该属于线程2的锁进行删除,这就是误删别人锁的情况说明

解决: setnx获取锁时,设置一个指定的唯一值(例如:uuid);释放前获取这个值,判断是否自己的锁
在这里插入图片描述

问题:删除操作缺乏原子性。
场景:

  1. index1执行删除时,查询到的lock值确实和uuid相等
  2. index1执行删除前,lock刚好过期时间已到,被redis自动释放
  3. index2获取了lock
  4. index1执行删除,此时会把index2的lock删除

解决方案:没有一个命令可以同时做到判断 + 删除,所有只能通过其他方式实现(LUA脚本

2.4. redis中的lua脚本

2.4.1 redis 并不能保证

redis采用单线程架构,可以保证单个命令的原子性,但是无法保证一组命令在高并发场景下的原子性

如果redis客户端通过lua脚本把3个命令一次性发送给redis服务器,那么这三个指令就不会被其他客户端指令打断。Redis 也保证脚本会以原子性的方式执行: 当某个脚本正在运行的时候,不会有其他脚本或 Redis 命令被执行。 这和使用 MULTI/ EXEC 包围的事务很类似。

2.4.2 lua介绍

2.5. 使用lua保证删除原子性

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

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

相关文章

亿信华辰举行制造业数字化转型研讨会,解密数字化最佳实践

制造业是国家经济命脉所系,推进制造业数字化转型已成为发展数字经济的重中之重。今天(5月9日)上午,亿信华辰携手沙丘社区成功举办“制造业数字化转型研讨会”,1.3万人线上观看,汇聚华为、鼎捷软件、亿信华辰…

uniapp实现预约时间选择弹窗组件

做了个组件&#xff0c;实现出当日预约时间组件&#xff0c;效果图如下 废话不多说&#xff0c;直接上代码&#xff0c;代码简单&#xff0c;参数自己任意改 <template><view class"inventory"><u-popup :show"show" :round"10"…

OpenAI重磅官宣ChatGPT安卓版本周发布,现已开启下载预约,附详细预约教程

7月22号&#xff0c;OpenAI 突然宣布&#xff0c;安卓版 ChatGPT 将在下周发布&#xff01;换句话说&#xff0c;本周安卓版 ChatGPT正式上线&#xff01; 最早&#xff0c;ChatGPT仅有网页版。 今年5月&#xff0c;iOS版ChatGPT正式发布&#xff0c;当时OpenAI表示Android版将…

【C++ 重要知识点总结】自定义类型-类和结构体

类 类的基本特性 数据抽象和封装继承多态 1 类的构成——抽象 概念 数据抽象是一种依赖于接口和实现的分离的编程技术。类的接口包括用户所能执行的操作&#xff1b;类的实现包括类的数据成员、负责接口实现的函数体以及定义类所需要的的各种私有函数。封装实现了类的接口和实…

Java使用FFmpeg实现mp4转m3u8

Java使用FFmpeg实现mp4转m3u8 前言FFmpegM3U8 一、需求及思路分析二、安装FFmpeg1.windows下安装FFmpeg2.linux下安装FFmpegUbuntuCentOS 三、代码实现1.引入依赖2.修改配置文件3.工具类4.Controlle调用5.Url转换MultipartFile的工具类 四、播放测试1.html2.nginx配置3.效果展示…

Web3.0:已经开启的互联网革命!

1 痛点 2 web发展形态 只读、封闭式、协作式。 3 一个高度联系、全球统一的数字经济体 去中心化架构通过计算几余打破数据垄断&#xff0c;同时实现数字确权大量的功能依靠智能合约自动实现&#xff0c;运转效率大大提升DAO大量涌现&#xff0c;全球范围实现资源配置 4 特…

【Element-ui】学习与使用

网站快速成型工具Element&#xff0c;一套为开发者、设计师和产品经理准备的基于vue2.0的桌面端组件库 安装 npm i element-ui -S 在项目中安装element-ui&#xff0c;安装了以后查看package.json中的依赖中有没有element-ui的版本&#xff0c;如果有&#xff0c;则说明安装成功…

Spring Boot 自定义启动画面

文章目录 自定 Banner获取属性设置颜色实操关闭 Banner参考 我们启动项目的之后&#xff0c;会在控制台上看到类似下面的画面&#xff1a; 那么&#xff0c;我们是否可以自定义呢&#xff1f; 肯定可以 自定 Banner 上面的截图信息就是 Banner 信息&#xff0c;我们可以在项目…

在Chrome(谷歌浏览器)中安装Vue.js devtools开发者工具及解决Vue.js not detected报错

文章目录 一、Vue.js devtools开发者工具安装1.打开谷歌浏览器——点击扩展程序——选择管理扩展程序2.先下载添加一个谷歌助手到扩展程序中&#xff08;根据提示进行永久激活&#xff09;3.点击谷歌浏览器的应用商店4.输入Vue.js devtools——搜索——选择下载 二、解决Vue.js…

如何为WordPress博客网站配置免费域名HTTPS证书

文章目录 如何为WordPress博客网站配置免费域名HTTPS证书前置条件&#xff1a;步骤1 申请免费的域名HTTPS证书步骤2 将HTTP证书配置到cpolar的配置文件中2.1 创建证书文件夹2.2 修改cpolar配置文件2.3 重启cpolar服务2.4 查看后台Wordpress隧道是否在线正常2.5 用浏览器打开站点…

MyBatis基础模块-类型转换模块

文章目录 1. 为什么需要类型转换模块2. TypeHandler 1. 为什么需要类型转换模块 执行sql&#xff0c;在PreparedStatement设置参数时&#xff0c;需要把java类型转换成jdbc类型&#xff0c;而从结果集中获取数据时&#xff0c;需要把jdbc类型转换为java类型。 2. TypeHandle…

Linux操作系统~必考面试题⑧

1、pwd 命令 pwd 命令用于查看当前工作目录路径。 实例&#xff1a; 查看当前路径 pwd 查看软链接的实际路径 pwd -P 2、rmdir 命令 从一个目录中删除一个或多个子目录项&#xff0c;删除某目录时也必须具有对其父目录的写权限。 注意&#xff1a;不能删除非空目录实例&…

Linux系统MySQL中用户的权限管理

本节主要学习用户权限管理的概述&#xff0c;用户权限类型&#xff0c;用户赋权&#xff0c;权限删除&#xff0c;用户删除等。 目录 一、概述 二、用户权限类型 三、用户赋权 四、权限删除 五、用户删除 一、概述 数据库用户权限管理是数据库系统中非常重要的一个方面&am…

统一观测丨使用 Prometheus 监控 Cassandra 数据库最佳实践

作者&#xff1a;元格 本篇内容主要包括四部分&#xff1a;Cassandra 概览介绍、常见关键指标解读、常见告警规则解读、如何通过 Prometheus 建立相应监控体系。 Cassandra 简介 Cassandra 是什么&#xff1f; Apache Cassandra 是一个开源、分布式、去中心化、弹性可伸缩、…

Vue3封装函数组件(ElImageViewer)预览图片

目录结构 index.vue <template><el-image-viewer v-if"show" v-bind"$attrs" hide-on-click-modal close"show false" /> </template><script setup> import { ref, watch } from "vue" import { ElImageV…

Linux基础以及常用命令

目录 1 Linux简介1.1 不同应用领域的主流操作系统1.2 Linux系统版本1.3 Linux安装1.3.1 安装VMWare1.3.2 安装CentOS镜像1.3.3 网卡设置1.3.4 安装SSH连接工具1.3.5 Linux和Windows目录结构对比 2 Linux常用命令2.0 常用命令&#xff08;ls&#xff0c;pwd&#xff0c;cd&#…

mysql的一些知识整理

这里整理一些mysql相关的知识点&#xff0c;是自己不太熟悉的内容 varchar(n) 中 n 最大取值为多少 MySQL 规定除了 TEXT、BLOBs 这种大对象类型之外&#xff0c;其他所有的列&#xff08;不包括隐藏列和记录头信息&#xff09;占用的字节长度加起来不能超过 65535 个字节。 …

docker+Jenkins

拉取镜像 docker pull jenkins/jenkins启动容器 8080端口映射58080 jenkins_home 映射本地/data/下方便查看 docker run -d -p 58080:8080 -p 5000:50000 -v /data/jenkins_home:/var/jenkins_home -v /etc/localtime:/etc/localtime --name jenkins jenkins/jenkins访问ip:5…

Java多线程锁

多线程锁 本专栏学习内容又是来自尚硅谷周阳老师的视频 有兴趣的小伙伴可以点击视频地址观看 Synchronized Synchronized是Java中锁的一种实现方法&#xff0c;我们需要了解他锁在什么地方&#xff0c;锁的类型有哪些 阿里巴巴开发手册规定&#xff1a; 高并发时&#xff0c;同…

将Spring Session存储到Redis中实现持久化

文章目录 Session持久化1. 添加依赖2. 配置redis连接信息3. 存储和读取session从Redis Session持久化 1. 添加依赖 在项目中添加session依赖和redis依赖&#xff0c;如下所示&#xff1a; <dependency><groupId>org.springframework.boot</groupId><art…