当前位置: 首页 > news >正文

【JAVA高级】如何使用Redis加锁和解锁(一)、Lua脚本执行原理及流程

文章目录

    • 加锁
      • 方法一:使用SETNX命令结合EXPIRE命令
      • 方法二:使用SET命令的扩展参数(NX和PX)
      • 方法三:使用Lua脚本
    • 解锁
      • 方法一:简单删除key
      • 方法二:使用Lua脚本验证后删除key
    • Lua脚本的执行原理:
      • 执行原理
      • 原子性保证
      • 注意事项
      • Lua示例:解锁

在Redis中加锁和解锁通常是通过Redis的原子性命令来实现的,以保证操作的原子性和线程安全。
以下是在Redis中加锁和解锁的详细步骤和注意事项:

加锁

方法一:使用SETNX命令结合EXPIRE命令

1.SETNX命令:SETNX是“SET if Not eXists”的缩写,它会在指定的key不存在时设置key的值。如果key已经存在,则命令不执行任何操作。

  • 命令格式:SETNX key value
  • 如果key不存在,设置key的值并返回1(表示加锁成功)。
  • 如果key已存在,不做任何操作并返回0(表示加锁失败)。

2.EXPIRE命令:为防止死锁,需要在加锁后设置一个过期时间。

  • 命令格式:EXPIRE key seconds
  • 设置key的过期时间,单位为秒。

注意:由于SETNX和EXPIRE是两个命令,它们之间可能存在时间差,这可能导致在SETNX和EXPIRE命令之间,Redis服务器崩溃或其他问题导致锁无法正确释放。因此,这种方法存在潜在的安全隐患。

方法二:使用SET命令的扩展参数(NX和PX)

Redis 2.6.12及以上版本支持SET命令的NX和PX选项,可以一次性完成加锁和设置过期时间的操作,从而避免上述安全隐患。

命令格式:SET key value NX PX milliseconds

  • NX:只在key不存在时设置key的值。
  • PX:设置key的过期时间,单位为毫秒。
    如果命令执行成功,则表示加锁成功;如果因为key已存在而执行失败,则表示加锁失败

方法三:使用Lua脚本

Lua脚本可以确保加锁和设置过期时间的原子性。

local lockKey = KEYS[1]  
local lockValue = ARGV[1]  
local lockTime = tonumber(ARGV[2])  
if redis.call('setnx', lockKey, lockValue) == 1 then  redis.call('expire', lockKey, lockTime)  return 1  
else  return 0  
end

使用EVAL命令执行Lua脚本。

解锁

解锁操作通常是通过删除Redis中的key来实现的。但是,直接删除key可能会存在安全风险,因为任何客户端都可以删除key,从而解锁。因此,解锁操作通常需要验证当前客户端是否是锁的持有者。

方法一:简单删除key

如果不考虑安全因素,可以直接使用DEL命令删除key来解锁。

  • 命令格式:DEL key
    但是,这种方法不推荐在生产环境中使用,因为它无法验证锁的持有者。

方法二:使用Lua脚本验证后删除key

为了确保解锁的安全性,可以使用Lua脚本来验证当前客户端是否是锁的持有者,然后再删除key。

-- KEYS[1] 是锁的key  
-- ARGV[1] 是锁的持有者(即客户端的唯一标识符)  local lockKey = KEYS[1]  
local lockValue = ARGV[1]  -- 检查锁是否存在,并且锁的值是否与客户端提供的值相匹配  
if redis.call('get', lockKey) == lockValue then  -- 如果匹配,则删除锁  return redis.call('del', lockKey)  
else  -- 如果不匹配,则不执行任何操作,并返回0表示解锁失败  return 0  
end

使用EVAL命令执行Lua脚本。
这种方法通过验证锁的值来确保只有锁的持有者才能解锁,从而提高了系统的安全性。

在Redis中加锁和解锁时,应优先考虑使用SET命令的扩展参数(NX和PX)或Lua脚本来确保操作的原子性和安全性。同时,为了避免死锁的发生,应为锁设置合理的过期时间。在解锁时,应验证锁的持有者身份,确保只有锁的持有者才能解锁。

Lua脚本的执行原理:

Lua脚本在Redis中的实现原理主要依赖于Redis服务器对Lua脚本的支持。Redis从2.6版本开始引入了Lua脚本功能,允许用户将一系列Redis命令封装在Lua脚本中,然后一次性发送给Redis服务器执行。这种方式有几个重要的优点,包括减少网络开销、保证命令的原子性执行以及简化客户端逻辑。

执行原理

  • 脚本发送:
    客户端将Lua脚本以字符串的形式发送给Redis服务器。脚本中可以包含任意数量的Redis命令,这些命令会按照脚本中的顺序执行。
  • 脚本加载:
    Redis服务器接收到Lua脚本后,会将其加载到内存中。这一步主要是将脚本字符串存储起来,以便后续执行。
  • 脚本执行:
    当需要执行脚本时,Redis服务器会启动一个Lua环境(通常是基于LuaJIT或标准Lua解释器),并将脚本字符串传递给这个环境进行执行。在脚本执行期间,Redis服务器会暂停处理其他客户端的命令(或者将它们排入队列),以确保脚本的原子性执行。
  • 脚本内部操作:
    Lua脚本内部可以使用Redis提供的Lua库来执行Redis命令。这些命令会被封装成Lua函数,脚本可以直接调用这些函数来与Redis数据库进行交互。例如,脚本可以使用redis.call()函数来执行Redis命令,并获取命令的返回结果。
  • 结果返回:
    脚本执行完毕后,Lua环境会将脚本的最后一个返回值(或所有返回值,取决于客户端的请求)返回给Redis服务器。Redis服务器再将这个值(或这些值)发送给客户端。
  • 脚本清理:
    如果脚本执行成功并返回了结果,Redis服务器会清理与脚本相关的资源,包括Lua环境中的变量和Redis命令的执行结果等。如果脚本执行过程中发生了错误,Redis服务器会记录错误信息,并可能将错误信息返回给客户端。

原子性保证

Lua脚本在Redis中的执行是原子的,这意味着在脚本执行期间,Redis服务器不会处理其他客户端的命令。这种原子性保证是通过Redis服务器内部的机制来实现的,具体来说,Redis服务器在执行Lua脚本时会使用一种称为“脚本锁”的机制来阻塞其他客户端的命令。

这种原子性保证对于实现分布式锁等需要高度一致性的操作非常重要。通过使用Lua脚本,我们可以确保在加锁和解锁的过程中,Redis命令的执行不会被其他客户端的命令打断,从而避免了竞态条件的发生。

注意事项

  • 脚本超时:Redis允许为Lua脚本设置最大执行时间(通过lua-time-limit配置项),以防止脚本执行时间过长导致Redis服务器无响应。如果脚本执行时间超过了限制,Redis服务器将中断脚本的执行并返回错误。
  • 内存使用:Lua脚本在Redis服务器中执行时会占用一定的内存资源。如果脚本过大或过于复杂,可能会导致Redis服务器的内存使用过高。因此,在编写Lua脚本时需要注意内存的使用情况。
  • 脚本缓存:Redis会将已经加载的Lua脚本缓存起来,以便后续再次执行时可以直接使用缓存的脚本字符串,而不需要重新发送脚本内容。这有助于减少网络开销和提高执行效率。但是,如果缓存的脚本过多,也可能会占用较多的内存资源。因此,在需要时可以通过SCRIPT FLUSH命令来清空脚本缓存。

Lua示例:解锁

-- KEYS[1] 是锁的key  
-- ARGV[1] 是锁的持有者(即客户端的唯一标识符)  local lockKey = KEYS[1]  
local lockValue = ARGV[1]  -- 检查锁是否存在,并且锁的值是否与客户端提供的值相匹配  
if redis.call('get', lockKey) == lockValue then  -- 如果匹配,则删除锁  return redis.call('del', lockKey)  
else  -- 如果不匹配,则不执行任何操作,并返回0表示解锁失败  return 0  
end

在Redis客户端中,你可以使用如下命令来执行这个Lua脚本:

-- 假设锁的key是"mylock",锁的持有者标识符是"myuniquevalue"  
EVAL "local lockKey = KEYS[1]; local lockValue = ARGV[1]; if redis.call('get', lockKey) == lockValue then return redis.call('del', lockKey) else return 0 end" 1 mylock myuniquevalue

这里,EVAL命令用于执行Lua脚本,1表示脚本中KEYS数组的长度(在这个例子中,我们只有一个key),mylock是传递给脚本的key,myuniquevalue是传递给脚本的持有者标识符。

如果脚本返回1,则表示锁已成功解锁;如果返回0,则表示锁不存在或当前客户端不是锁的持有者,因此无法解锁。

相关文章:

【JAVA高级】如何使用Redis加锁和解锁(一)、Lua脚本执行原理及流程

文章目录 加锁方法一:使用SETNX命令结合EXPIRE命令方法二:使用SET命令的扩展参数(NX和PX)方法三:使用Lua脚本 解锁方法一:简单删除key方法二:使用Lua脚本验证后删除key Lua脚本的执行原理&#…...

2024年使用宝塔面板轻松部署Java Web

以下是2024年最新图形化部署Java Web项目到CentOS系统的手把手教程: 一、准备工作 确保服务器环境:确保你的服务器已经安装了CentOS 7操作系统,并且已经安装了宝塔面板。如果还没有安装,可以参考之前的教程进行安装。下载Java W…...

闯关训练一:Linux基础

闯关任务:完成SSH连接与端口映射并运行hello_world.py 1.创建开发机 2.SSH连接 3. VS-Code 连接 选择 Linux 平台 ,输入密码 ,选择进入文件夹 4.端口映射 按照下文安装Docs pip install gradio 运行server.py import gradio as grdef …...

鸿蒙NEXT开发-ArkTS(基于最新api12稳定版)

注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下 如果大家觉得博主文章写的好的话,可以点下关注,博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…...

laravel延迟队列 取消未支付超时订单订单

1:生成待支付订单时,调用延迟队列 超过十五分钟未支付自动取消 use App\Jobs\endTask; use Illuminate\Support\Carbon; $resPost1 array("act" > "cy_order_cancel", "id" > $id); endTask::dispatch($resPos…...

解锁高效开发的秘密武器

在当今这个信息爆炸、技术日新月异的时代,编程工具的选择对于开发者来说至关重要。一个好的编程工具不仅能够简化代码编写,还能自动化任务、提升调试速度,甚至让团队协作更加顺畅。那么,哪款编程工具能让你的工作效率翻倍呢&#…...

【CSS】兼容处理

兼容前缀兼容查询 由于不同浏览器对CSS标准的支持程度不同,可能会导致在不同浏览器中出现样式差异。为了解决这个问题,需要采取一些措施来提高CSS的兼容性 兼容前缀 兼容前缀针对的浏览器-webkit-WebKit 内核浏览器,如:Safari 、…...

C语言线程

线程 多个进程中通过轮流使用CPU来完成自己的任务,如果多个进程的操作都一模一样那么CPU的开销就会很大,因为进程的地址都是私有的,如果CPU对相同的操作只执行一次,后面再遇到直接去获取即可,这样大大降低了CPU的开销…...

自闭症寄宿学校 vs. 日常教育:为孩子提供更多可能

在探索自闭症儿童的教育路径时,家长们往往面临一个重大的选择:是选择传统的日常教育环境,还是寻找专为自闭症儿童设计的寄宿学校?广州的星贝育园自闭症儿童寄宿制学校,以其独特的教育模式和全方位的关怀体系&#xff0…...

RxSwift系列(二)操作符

一、变换操作符:buffer、map、compactMap等 1.buffer buffer方法作用是缓冲组合,第一个参数是缓冲时间,第二个参数是缓冲个数,第三个参数是线程。缓存 Observable 中发出的新元素,当元素达到某个数量,或者…...

Gin框架简易搭建(3)--Grom与数据库

写在前面 项目地址 个人认为GORM 指南这个网站是相比较之下最为清晰的框架介绍 但是它在环境搭建阶段对于初学者而言不是很友好,尤其是使用mysql指令稍有不同,以及更新的方法和依赖问题都是很让人头疼的,而且这些报错并非逻辑上的&#xf…...

JavaScript模块化-CommonJS规范和ESM规范

1 ES6模块化 1.1 ES6基本介绍 ES6 模块是 ECMAScript 2015(ES6)引入的标准模块系统,广泛应用于浏览器环境下的前端开发。Node.js环境主要使用CommonJS规范。ESM使用import和export来实现模块化开发从而解决了以下问题: 全局作用…...

解决银河麒麟V10中的apt Lock异常

解决银河麒麟V10中的apt Lock异常 一、查找并杀掉apt进程二、删除锁文件三、重新尝试apt命令 💖The Begin💖点点关注,收藏不迷路💖 在使用银河麒麟V10的apt命令时,如果遇到lock异常,可以按以下步骤解决&…...

windows11环境安装lua及luarocks(踩坑篇)

一、lua安装及下载 官方地址: Lua Binaries Download 从这里就有坑了,下载后先解压win64_bin.zip,之后解压lib,用lib中的文件替换win64的,并把include文件夹复制过去,之后复制并重命名lua54,方…...

Glide基本用法及With方法源码解析

文章目录 引入优点 使用步骤导入依赖权限使用 其他用法占位符错误图片后备回调符圆角过渡动画大小调整gif缩略图 使用RequestOptions缓存机制设置缓存策略清理缓存 使用集成库OkHttpVolley with源码解析getRetrieverGlide.getinitializeGlide getRequestManagerRetriever Reque…...

html中的文本标签(含标签的实现案例)

目录 1.标题标签 2.标题标签的align属性 3.段落标签 4.水平线标签hr 5.换行标签br 6.文本样式标签font ​编辑7.文本格式化标签 8.文本语义标签 1)时间time标签 2)文本高亮Mark标签 3)cite标签 9.特殊字符标签 10.图像标签img 附录&#xff…...

通信协议感悟

本文结合个人所学,简要讲述SPI,I2C,UART通信的特点,限制。 1.同步通信 UART,SPI,I2C三种串行通讯方式,SPI功能引脚为CS,CLK,MOSI,MISO;I2C功能引…...

IDEA几大常用AI插件

文章目录 前言列表GPT中文版TalkXBito AIIDEA自带的AI 前言 最近AI、GPT特别火,IDEA里面又有一堆插件支持GPT,所以做个专题比较一下各个GPT插件 列表 先看idea的plugins里支持哪些,搜索“GPT”之后得到的,我用下来感觉第一第二和…...

51单片机学习第六课---B站UP主江协科技

DS18B20 1、基本知识讲解 2、DS18B20读取温度值 main.c #include<regx52.h> #include"delay.h" #include"LCD1602.h" #include"key.h" #include"DS18B20.h"float T; void main () {LCD_Init();LCD_ShowString(1,1,"temp…...

sadTalker本地编译

SadTalker一款开源的可生成逼真的人像动画的工具。它利用深度学习技术&#xff0c;根据输入的图像和音频&#xff0c;生成具有生动表情和动作的视频。用户可以通过上传照片或使用预设的模型&#xff0c;轻松创建个性化的动画内容. 以上是官网的图, 下边是本地部署生成的,效果差…...

强化学习核心概念与公式总结

强化学习核心概念与公式总结 1. 核心概念 1.1 智能体(Agent)和环境(Environment) 智能体:学习和做决策的实体环境:智能体交互的外部系统1.2 状态(State) 描述环境在特定时刻的情况1.3 动作(Action) 智能体可以执行的操作1.4 奖励(Reward) 环境对智能体动作的即时反馈1.5 策…...

基础算法--双指针【概念+图解+题解+解释】

更多精彩内容..... &#x1f389;❤️播主の主页✨&#x1f618; Stark、-CSDN博客 本文所在专栏&#xff1a; 数据结构与算法_Stark、的博客-CSDN博客 其它专栏&#xff1a; 学习专栏C语言_Stark、的博客-CSDN博客 项目实战C系列_Stark、的博客-CSDN博客​​​​​​ 座右铭&a…...

国产化系统/鸿蒙开发足浴店收银源码-收缩左侧———未来之窗行业应用跨平台架构

一、左侧展开后 二、代码 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head><title></title><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><style t…...

如何从硬盘恢复丢失/删除的视频

您是否想知道是否可以恢复已删除的视频&#xff1f; 幸运的是&#xff0c;您可以使用奇客数据恢复从硬盘驱动器、SD 卡和 USB 闪存驱动器恢复已删除的视频文件。 你有没有遇到过这样的情况&#xff1a;当你随机删除文件以释放空间时&#xff0c;你不小心按下了一些重要视频的…...

《Effective C++》第三版——设计与声明(1)

参考资料&#xff1a; 《Effective C》第三版 注意&#xff1a;《Effective C》不涉及任何 C11 的内容&#xff0c;因此其中的部分准则可能在 C11 出现后有更好的实现方式。 条款 18&#xff1a;让接口容易被正确使用&#xff0c;不易被误用 好的接口很容易被正确使用&…...

数值计算的程序设计问题举例

### 数值计算的程序设计问题 #### 1. 结构静力分析计算 **涉及领域**&#xff1a;工程力学、建筑工程 **主要问题**&#xff1a;线性代数方程组&#xff08;Linear Algebraic Equations&#xff09; **解释说明**&#xff1a; 在结构静力分析中&#xff0c;我们需要解决复杂的…...

Java之方法的使用

修饰符 返回值 方法名称&#xff08;形式参数&#xff09;{ } 当无参数的时候形式参数中什么都不写。 列如求两个数相加 修饰符可有可无。 方法重载&#xff1a; 1.方法名相同 2.参数列表不同 3。返回值不影响重载...

sudo 命令:掌握系统权限控制,实现安全高效管理

一、命令简介 ​sudo​ 命令允许系统管理员授权普通用户执行特定命令&#xff0c;并以管理员身份运行这些命令&#xff0c;通常需要输入用户自己的密码。 ​​ sudo 全称是"substitute user do"&#xff0c;意为“替用户做”&#xff0c;也就是“以另一个用户的身…...

AndroidStudio导入so文件

点击app 右键依次选择New-Floder-JNI Floder 创建jni目录 将需要的so文件拷贝到jni目录 在app目录下&#xff0c;build.gradle文件的android{}中添加&#xff1a; sourceSets {main{jniLibs.srcDirs [src/main/jni]}}点击一下Sync Project with Gradle Files 然后编译生成AP…...

Kuebernetes 群集基于 Docker 部署

Kuebernetes 群集基于 Docker 部署 实验报告资源列表基础环境一、准备 Docker1、安装 Docker 二、安装 Kubeadm 工具1、配置 yum 源2、安装 Kubeadm 工具 三、初始化 Master 节点1、配置 Master 节点2、常见故障 四、Node 节点加入集群五、部署网络插件&#xff08;CNI&#xf…...

wordpress的分类目录做成树/seo培训教程

文章目录一、题目1、题目描述2、基础框架3、原题链接二、解题报告1、思路分析2、时间复杂度3、代码详解三、本题小知识四、加群须知一、题目 1、题目描述 给你一个字符串数组 words&#xff0c;找出并返回数组中的第一个回文字符串 。如果不存在满足要求的字符串&#xff0c;返…...

中小企业网站建设价格/全网营销整合推广

近日&#xff0c;微软的EF团队发布了一个针对SQL Server的Sample Database Provider Entity Framework 5&#xff0c;支持EF的一些新特性。 这个新的Sample Provider支持如下EF 5的新特性&#xff1a; Spatial typesTable Valued Functions带有多个结果集的存储过程然而&#x…...

国外做内容网站/优化网络推广外包

大数据时代&#xff0c;什么最贵? 十年前&#xff0c;葛大爷曾说过&#xff0c;“21世纪什么最贵?”——“人才”&#xff0c;深以为然。只是&#xff0c;十年后的今天&#xff0c;大数据时代也带来了身价不断翻番的各种数据。由于急速拓展的网络带宽以及各种穿戴设备所带来…...

云南微网站搭建费用/百度竞价推广是什么工作

参考网址&#xff1a; https://www.jianshu.com/p/2a4a39e3704f转载于:https://www.cnblogs.com/maohuidong/p/10487729.html...

专业APP客户端做网站/国产搜什么关键词最好看

转自&#xff1a;https://juejin.cn/post/68982703130505379971.索引类型 keyof 索引类型查询操作符&#xff0c;可以获取泛型T上所有的 public 属性名构成联合类型class Person { name: string "胡先生" age: number 18 private UserId: number 123}typ…...

企业网站的公司和产品信息的介绍与网络营销关系/深圳网站制作推广

题目&#xff1a;原题链接&#xff08;中等&#xff09; 标签&#xff1a;广度优先搜索、深度优先搜索 解法时间复杂度空间复杂度执行用时Ans 1 (Python)O(N84)O(N8^4)O(N84)O(N)O(N)O(N)36ms (79.65%)Ans 2 (Python)Ans 3 (Python) 解法一&#xff1a; class Solution:_CHA…...