基于 Redis + Lua 脚本实现分布式锁,确保操作的原子性
1.加锁的Lua脚本: lock.lua
--- -1 failed
--- 1 success--- getLock key
local result = redis.call('setnx' , KEYS[1] , ARGV[1])
if result == 1 then--PEXPIRE:以毫秒的形式指定过期时间redis.call('pexpire' , KEYS[1] , 3600000)
elseresult = -1;-- 如果value相同,则认为是同一个线程的请求,则认为重入锁local value = redis.call('get' , KEYS[1])if (value == ARGV[1]) thenresult = 1;redis.call('pexpire' , KEYS[1] , 3600000)end
end
-- 如果获取锁成功,则返回 1
return result
2.解锁的Lua脚本: unLock.lua
if redis.call('get', KEYS[1]) == ARGV[1]thenreturn redis.call('del', KEYS[1])elsereturn 0
end
3.将资源文件放在资源文件夹下

4.Java中调用lua脚本
1)获取文件方式
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Arrays;/*** @Author: best_liu* @Description:* @Date Create in 14:04 2023/10/26* @Modified By:*/
@Slf4j
@RestController
public class LuaLock {@Autowiredprivate RedisTemplate redisTemplate;@GetMapping(value = "/getLock")public Long getLock() {DefaultRedisScript<Long> script = new DefaultRedisScript<Long>();script.setResultType(Long.class);
// 获取lua文件方式script.setScriptSource(new ResourceScriptSource(new ClassPathResource("script/lock.lua")));Long execute = (Long) redisTemplate.execute(script, Arrays.asList("best_liu"),"best_liu20231026150600");return execute;}
}
2)lua字符串方式
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Arrays;/*** @Author: best_liu* @Description:* @Date Create in 14:04 2023/10/26* @Modified By:*/
@Slf4j
@RestController
public class LuaLock {@Autowiredprivate RedisTemplate redisTemplate;@GetMapping(value = "/getLock")public Long getLock() {DefaultRedisScript<Long> script = new DefaultRedisScript<Long>();script.setResultType(Long.class);
// 获取lua文件方式
// script.setScriptSource(new ResourceScriptSource(new ClassPathResource("script/lock.lua")));String lua = "local result = redis.call('setnx' , KEYS[1] , ARGV[1])\n" +"if result == 1 then\n" +" redis.call('pexpire' , KEYS[1] , 3600000)\n" +"else\n" +" result = -1;\n" +" local value = redis.call('get' , KEYS[1])\n" +" if (value == ARGV[1]) then\n" +" result = 1;\n" +" redis.call('pexpire' , KEYS[1] , 3600000)\n" +" end\n" +"end\n" +"return result";script.setScriptText(lua);Long execute = (Long) redisTemplate.execute(script, Arrays.asList("best_liu"),"best_liu20231026150600");return execute;}
}
5.jedis调用Lua脚本实现分布式重试锁
1)引入jedis依赖
<!-- jedis --><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.0</version></dependency>
2)jedis调用lua
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;@Slf4j
@RestController
public class LuaLock {@GetMapping(value = "/getLock")public Long getLock() {//获取连接Jedis jedis = new Jedis("127.0.0.1", 6379);String lua = "local result = redis.call('setnx' , KEYS[1] , ARGV[1])\n" +"if result == 1 then\n" +" redis.call('pexpire' , KEYS[1] , ARGV[2])\n" +"else\n" +" result = -1;\n" +" local value = redis.call('get' , KEYS[1])\n" +" if (value == ARGV[1]) then\n" +" result = 1;\n" +" redis.call('pexpire' , KEYS[1] , ARGV[2])\n" +" end\n" +"end\n" +"return result";List<String> keys = new ArrayList<>();List<String> values = new ArrayList<>();keys.add("best_liu");values.add("best_liu20231026150600");values.add("3600000");Object result = jedis.eval(lua, keys, values);System.out.println(result);return 1L;}
}
相关文章:
基于 Redis + Lua 脚本实现分布式锁,确保操作的原子性
1.加锁的Lua脚本: lock.lua --- -1 failed --- 1 success--- getLock key local result redis.call(setnx , KEYS[1] , ARGV[1]) if result 1 then--PEXPIRE:以毫秒的形式指定过期时间redis.call(pexpire , KEYS[1] , 3600000) elseresult -1;-- 如果value相同&…...
vue源码分析(七)—— createComponent
文章目录 前言一、createComponent 参数说明二、createComponent 源码详解1.baseCtor的实际指向2.extend 方法3.判断Ctor是否是函数的判断4.installComponentHooks方法5.返回一个带标识的组件 vnode 前言 createComponent文件的路径: src\core\vdom\create-componen…...
vue实现图片分页
本小节学会使用v-show和click 、v-bind,v-bind可以简写为: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"…...
Baklib专注:企业数字内容体验与知识管理
随着科技的发展,消费者对数字体验的依赖程度攀升,品牌正面临着越来越大的压力。数字化体验作为当下最热门的话题之一,无论是传统企业还是互联网企业,都在积极探索创新方案和具体措施,从而提高用户的数字化体验…...
C++ 标准库随机数:std::default_random_engine
库头文件 #include <random> // 通过种子值设置随机数生成器 std::default_random_engine rng(seed);// 不设置种子值,使用默认值 std::default_random_engine rng; // 生成一个0到9之间的随机整数 int random_int rng() % 10;// 生成一个0到1之间的随机浮…...
Python requests之Cookie
视频版教程:一天掌握python爬虫【基础篇】 涵盖 requests、beautifulsoup、selenium 在某些需要登录的网站或者或者应用,假如我们需要抓取登录后的内容,技术上本质通过session会话实现。服务器端存会话信息,浏览器通过Cookie携带…...
【嵌入式项目应用】__嵌入式中,映射表的应用例子!
目录 一、嵌入式中的映射表是什么? 二、映射表在串口数据解析中的应用 1. 数据结构 2. 指令、函数映射表 3. 串口解析函数实现 三、映射表在UI设计中的应用 1. 数据结构 2. 函数映射表 3. 定义两个变量保存当前场景和上一个场景 4. 按下Up按键 跳转到指定场…...
react中的useState和useImmer的用法
文章目录 一、useState1. 更新基本类型数据2. 更新对象3. 更新嵌套对象4. 更新数组5.更新数组对象 二、Immer1. 什么是Immer2. 使用use-immer更新嵌套对象3. 使用useImmer更新数组内部的对象 一、useState react中文官网教程 1. 更新基本类型数据 在函数式组件中,…...
Can‘t compile code “launch: program <program_path> does not exist “
StackOverflow上有一个类似的提问 我的情况很特殊,上面的回答没有解决我的问题,最后我发现是我的cpp文件名称为数字开头(类似于1_floy.cpp),把名字里的数字挪到后面就好了。。。。。...
Mac电脑上升级nodejs
第一步,先查看本机node.js版本: node -v 第二步,清除node.js的cache: sudo npm cache clean -f 第三步,安装 n 工具,这个工具是专门用来管理node.js版本的,别怀疑这个工具的名字,…...
基于单片机的太阳跟踪系统的设计
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式 文章目录 概要 一、设计的主要内容二、硬件电路设计2.1跟踪控制方案的选择2.1.1跟踪系统坐标系的选择2.2系统总体设计及相关硬件介绍…...
V3Det大规模词汇视觉检测数据集与LaRS海上全景障碍物检测数据集
V3Det与LaRS是ICCV2023上发表的数据集工作,规模都比较大,后续有可能会用到,因此记录下来。 V3Det: Vast Vocabulary Visual Detection Dataset Paper: https://arxiv.org/abs/2304.03752 URL: https://v3det.openxlab.org.cn/ 在现实世界中…...
ubuntu(18.04) 安装 blast
1、下载 https://ftp.ncbi.nlm.nih.gov/blast/executables/blast/LATEST/2、解压,配置环境变量 tar zvxf ncbi-blast-2.14.1-x64-linux.tar.gz解压后改名为 blast 配置环境变量,可以不配置 使用的时候直接绝对路径使用 vim ~/.bashrc 将下面添加道最…...
3.2每日一题(定积分求抽水做工问题)
1、画图,把题目的容器画出来:球形容器,半径为R 2、根据容器的形状进行分析: 抽水的实质是不同深度的水抽出去走的位移是不一样的>抽水的过程 : (1)先考虑深度为 x到xdx 的薄层水抽出去做多少…...
c语言基础:L1-063 吃鱼还是吃肉
国家给出了 8 岁男宝宝的标准身高为 130 厘米、标准体重为 27 公斤;8 岁女宝宝的标准身高为 129 厘米、标准体重为 25 公斤。 现在你要根据小宝宝的身高体重,给出补充营养的建议。 输入格式: 输入在第一行给出一个不超过 10 的正整数 N&am…...
<if> 标签中使用了不正确的语法。在 XML 中,<if> 标签不需要使用 <![CDATA[ ... ]]> 将条件语句包装起来。 否则会报错
标签中使用了不正确的语法。在 XML 中, 标签不需要使用 <![CDATA[ ... ]]> 将条件语句包装起来。 否则会报错...
Ubuntu 诞生 19 年
导读2004 年 10 月 20 日,Ubuntu 4.10 正式发布,代号‘Warty Warthog’。 作为 Ubuntu 第一个版本,4.10 问世后立刻受到广大 Linux 用户欢迎。它搭载了当时最新的 GNOME 2.8 桌面环境,以及一系列实用软件,比如 Mozilla…...
JVM进阶(3)
一)什么是垃圾? 垃圾指的是在应用程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾,如果不及时的针对内存中的垃圾进行清理,那么这些垃圾对象所占用的内存空间可能一直保留到应用程序结束,被保留的空间无法…...
Qt QWidget、QDialog、QMainWindow的区别
QWidget QWidget是Qt框架中最基础的窗口类,可以理解为用户界面的最基本单元。QWidget类提供了一个空白窗口,可以通过继承该类来创建自定义的窗口类。QWidget类提供了基本的窗口属性和方法,如大小、位置、标题、图标等。 QDialog QDialog是…...
软考 系统架构设计师系列知识点之设计模式(10)
接前一篇文章:软考 系统架构设计师系列知识点之设计模式(9) 所属章节: 老版(第一版)教材 第7章. 设计模式 第2节. 设计模式实例 相关试题 9. 某软件公司欲设计一款图像处理软件,帮助用户对拍…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
轻量级Docker管理工具Docker Switchboard
简介 什么是 Docker Switchboard ? Docker Switchboard 是一个轻量级的 Web 应用程序,用于管理 Docker 容器。它提供了一个干净、用户友好的界面来启动、停止和监控主机上运行的容器,使其成为本地开发、家庭实验室或小型服务器设置的理想选择…...
LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考
目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候,显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...
