前言、为什么要用 Lua?

  • 多步操作合并为一步,保证原子性。

  • 减少网络通信次数。

  • 下推逻辑到 Redis,提高性能。

一、Redis 使用 Lua 脚本的两种方式

方式一:使用 --eval 执行脚本文件

这种方式 需要先写一个 Lua 文件

📌 示例:创建一个 setname.lua 文件,内容如下:

-- KEYS[1] 表示 key
-- ARGV[1] 表示 value
-- ARGV[2] 表示过期时间(秒)
return redis.call("set", KEYS[1], ARGV[1], "EX", ARGV[2])

在命令行执行:

redis-cli --eval setname.lua name , czq 5

📌 解释:

  • --eval setname.lua namename 传给 KEYS[1]

  • 逗号 , 后面的是 ARGV"czq"ARGV[1]5ARGV[2]

执行效果:

OK

再验证:

get name
"czq"
ttl name
(integer) 5   # 有效期 5 秒

方式二:使用 eval 命令直接写脚本

这种方式 直接在 redis-cli 里执行 Lua 代码,不需要写文件。

📌 示例:

redis-cli

进入 redis-cli 后执行:

eval "return redis.call('set', KEYS[1], ARGV[1], 'EX', ARGV[2])" 1 name czq 5

📌 解释:

  • "return redis.call(...)" → 直接写 Lua 代码

  • 1 表示有 1 个 KEYS 参数

  • name → KEYS[1]

  • czq → ARGV[1]

  • 5 → ARGV[2]

结果:

OK

二者区别

  • redis-cli --eval ... 是在 Linux shell 里执行,不用手动进入交互模式。(方式一)

    • redis-cli --eval lua文件的路径/lua的名称.lua....

  • eval "..." 必须进入 redis-cli 交互模式才能用。(方式二)


三、KEYS 和 ARGV 的作用

在 Redis 的 Lua 脚本里:

  • KEYS → 存放 key(可以有多个,KEYS[1]、KEYS[2]...)

  • ARGV → 存放参数(value、过期时间等)

📌 示例:

-- 假设脚本里是这样:
return "KEY=" .. KEYS[1] .. ", VALUE=" .. ARGV[1] .. ", TTL=" .. ARGV[2]

执行:

eval "return 'KEY='..KEYS[1]..', VALUE='..ARGV[1]..', TTL='..ARGV[2]" 1 name czq 5

输出结果:

"KEY=name, VALUE=czq, TTL=5"

👉 总结:

  • KEYS 专门用来传 key(好处是 Redis 会自动进行 key hash 定位,支持集群)

  • ARGV 专门用来传其他参数(value、过期时间等)


四、Spring Boot 使用 Lua 脚本

 这个例子是SETNX + 过期时间结合成的原子性,通常用于 分布式锁一人一单 之类的业务。

在 Spring Boot 里也可以执行这个 Lua 脚本。

📌 示例代码:

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.stereotype.Service;import java.util.Collections;@Service
public class RedisLuaService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 使用 SETNX + EX 实现键值设置(例如分布式锁)*/public Object setNxWithExpire() {// 1️⃣ Lua 脚本// 先尝试 SETNX,如果成功,再设置过期时间String lua ="if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then " +"   redis.call('expire', KEYS[1], ARGV[2]) " +"   return 1 " +"else " +"   return 0 " +"end";// 2️⃣ 封装脚本DefaultRedisScript<Long> script = new DefaultRedisScript<>();script.setScriptText(lua);script.setResultType(Long.class);// 3️⃣ 执行脚本return redisTemplate.execute(script,     Arrays.asList("lock_key"), // KEYS[1] 例如分布式锁的 key,keys 参数要求传的是一个 List<K>,定义成 List<String>,方便支持多个 key。"czq", "5" // ARGV[1] = value (锁的标识),ARGV[2] = 过期时间秒);}
}
✅ 使用说明
Object result = redisLuaService.setNameWithExpireIfAbsent();
System.out.println(result); 
  • 返回 1:设置成功(key 原本不存在)。

  • 返回 0:设置失败(key 已经存在)。

Redis 里结果:

127.0.0.1:6379> get name
"czq"
127.0.0.1:6379> ttl name
(integer) 5

📌 改造后的好处

  1. 保证原子性

    • 用 Lua 保证 SETNXEXPIRE 是在 Redis 内部一次性执行,避免 SETNX 成功但服务挂掉导致没有设置过期时间,从而出现“死锁”

  2. 分布式锁场景

    • SETNX 确保只有一个客户端能拿到锁。

    • EXPIRE 确保即使客户端崩溃,锁也会在过期时间后自动释放。

  3. 一人一单 / 防重提交

    • SETNX 用来保证某个 key(比如订单 ID 或用户 ID)只能被设置一次。

    • EXPIRE 防止 key 永久占用,给系统自动恢复的能力。

  4. 返回值可控

    • 返回 1 表示设置成功(抢到锁 / 成功下单)。

    • 返回 0 表示设置失败(别人已经抢到锁 / 已经下过单

📌小贴士:

        Redis 本身就支持 SET key value EX seconds NX 命令(SETNX + EXPIRE的原子性组合版),它是原子性的,不需要 Lua。Spring 的 RedisTemplate 里也可以直接调用,避免自己写 Lua。

@Service
public class RedisService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;public Boolean setIfAbsentWithExpire(String key, String value, long seconds) {return redisTemplate.opsForValue().setIfAbsent(key, value, seconds, TimeUnit.SECONDS);}
}
优点

        ✅ 原子性保证(内部就是单条 Redis 命令)。
✅ 使用简单,无需写 Lua。
✅ 代码更可读,Spring 已经封装好了。

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

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

相关文章

基于 C 语言的网络单词查询系统设计与实现(客户端 + 服务器端)

一、项目概述本文将介绍一个基于 C 语言开发的网络单词查询系统&#xff0c;该系统包含客户端和服务器端两部分&#xff0c;支持用户注册、登录、单词查询及历史记录查询等功能。系统采用 TCP socket 实现网络通信&#xff0c;使用 SQLite 数据库存储用户信息、单词数据及查询记…

《JAVA EE企业级应用开发》第一课笔记

《JAVA EE企业级应用开发》第一课笔记 文章目录《JAVA EE企业级应用开发》第一课笔记课程主题&#xff1a;三层架构与SSM框架概述一、核心架构&#xff1a;三层架构 (MVC)1. 表现层 (Presentation Layer)2. 业务逻辑层 (Business Logic Layer)3. 数据持久层 (Data Persistence …

RT-DETR网络结构

1.前言 本章主要来介绍下RT-DETR的网络结构,参考的依旧是ultralytics实现的RT-DETR-L,代码如下: ultralytics/ultralytics: Ultralytics YOLO 🚀 首先谈谈我对RT-DETR的浅显认识,他不像是YOLOv8这种纯CNN实现的网络,也不像是Vit这种以Transformer实现的网络,他是前一…

Python 文件复制实战指南:从基础操作到高效自动化的最佳实践

Python 文件复制实战指南:从基础操作到高效自动化的最佳实践 1. 引言:文件复制为何是自动化的核心能力? 在日常开发与运维工作中,文件复制是一项基础却至关重要的操作。无论是备份日志、同步配置、部署代码,还是批量迁移数据,都离不开对文件的精准复制与路径管理。而 Py…

WebSocket的基本使用方法

一. 与HTTP对比WebSocket 是一种在单个 TCP 连接上实现全双工&#xff08;双向&#xff09;通信的网络协议&#xff0c;它解决了传统 HTTP 协议 “请求 - 响应” 模式的局限性&#xff0c;让客户端&#xff08;如浏览器&#xff09;和服务器能建立持久连接&#xff0c;实现实时…

架构选型:为何用对象存储替代HDFS构建现代数据湖

在过去十余年的大数据浪潮中&#xff0c;Hadoop及其核心组件HDFS&#xff08;Hadoop分布式文件系统&#xff09;无疑是整个技术生态的基石。它开创性地解决了海量数据的分布式存储难题&#xff0c;支撑了无数企业从数据中挖掘价值。然而&#xff0c;随着数据规模的指数级增长以…

智能养花谁更优?WebIDE PLOY技术与装置的结合及实践价值 —— 精准养护的赋能路径

一、WebIDEPLOY 技术支撑下的智能养花系统核心构成在 WebIDEPLOY 技术的框架下&#xff0c;智能养花装置形成了一套精准协同的闭环系统&#xff0c;其核心在于通过技术整合实现 “监测 - 决策 - 执行 - 远程交互” 的无缝衔接&#xff0c;让植物养护更贴合城市居民的生活节奏。…

基于llama.cpp在CPU环境部署Qwen3

大家好,我是奇文王语,NLP爱好者,长期分享大模型实战技巧,欢迎关注交流。 最近两天在研究如何使用小规模参数的模型在CPU环境上进行落地应用,比如模型Qwen3-0.6B。开始使用Transformers库能够正常把模型服务进行部署起来,但是通过测试速度比较慢,用户的体验会比较差。 …

‌NAT穿透技术原理:P2P通信中的打洞机制解析‌

要说网络世界里的 “幕后功臣”&#xff0c;NAT 绝对得算一个&#xff0c;大家伙儿有没有琢磨过&#xff0c;为啥家里的电脑、手机&#xff0c;还有公司那一堆设备&#xff0c;都能同时连上网&#xff0c;还不打架呢&#xff1f; NAT 这东西&#xff0c;全名叫网络地址转换&am…

工业 5G + AI:智能制造的未来引擎

工业 5G AI&#xff1a;智能制造的未来引擎 文章目录工业 5G AI&#xff1a;智能制造的未来引擎摘要一、为什么工业需要 5G&#xff1f;二、工业 5G 的典型应用场景1. 智能制造工厂2. 远程控制与运维3. 智慧物流与仓储4. 能源、电力、矿山5. 智慧港口与交通三、成功案例解析1…

边缘计算设备 RK3576芯片

RK3576是瑞芯微&#xff08;Rockchip&#xff09;公司专为人工智能物联网&#xff08;AIoT&#xff09;市场精心设计的一款高算力、高性能及低功耗的国产化应用处理器。该处理器采用了先进的ARM架构&#xff0c;集成了四个ARM Cortex-A72高性能核心与四个ARM Cortex-A53高效能核…

ROS1系列学习笔记之T265的Python数据订阅显示、串口输出到凌霄飞控,以及开机自启动设置等一些问题处理方法(持续更新)

前言 关于T265的环境配置与安装&#xff0c;在前两期的ROS笔记中已经提及&#xff0c;包括英特尔本家的SDK安装&#xff0c;以及对应支持版本的ROS支持开发工具包。 ROS1系列学习笔记之Linux&#xff08;Ubuntu&#xff09;的环境安装、依赖准备、踩坑提示&#xff08;硬件以…

UART控制器——ZYNQ学习笔记14

UART 控制器是一个全双工异步收发控制器&#xff0c; MPSoC 内部包含两个 UART 控制器&#xff0c; UART0 和 UART1。每一个 UART 控制器支持可编程的波特率发生器、 64 字节的接收 FIFO 和发送 FIFO、产生中断、 RXD 和TXD 信号的环回模式设置以及可配置的数据位长度、停止位和…

C++ 登录状态机项目知识笔记

C 登录状态机项目知识笔记 1. 项目源码 1.1 login_state_machine.h #pragma once#include <string>// 登录状态枚举 enum class LoginState { IDLE, AUTHENTICATING, SUCCESS, FAILURE, LOCKED };// 登录事件枚举 enum class LoginEvent { REQUEST, SUCCESS, FAILURE, RE…

docker-nacos-v3

nacos官网&#xff1a; Redirecting to: https://nacos.io/ 服务发现和服务健康监测 Nacos 支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用 原生SDK、OpenAPI、或一个独立的Agent TODO注册 Service 后&#xff0c;服务消费者可以使用DNS TODO 或HTTP&API查找和发现服…

DevOps 详解:文化、实践与工具链

目录一、DevOps 定义与核心目标二、DevOps 关键原则与实践1. 持续集成&#xff08;CI&#xff0c;Continuous Integration&#xff09;2. 持续交付&#xff08;CD&#xff0c;Continuous Delivery&#xff09;3. 持续部署&#xff08;Continuous Deployment&#xff09;4. 监控…

人工智能之数学基础:常用的连续型随机变量的分布

本文重点 本文将介绍概率中非常重要的连续型随机变量的分布,主要有均匀分布、指数分布、正态分布 均匀分布 若随机变量X的概率密度为: 如果概率密度函数如上所示,则称X服从区间[ a, b]上的均匀分布,记作X~U[a,b] 均匀分布的概率密度函数的计算如下: 指数分布 指数分布…

【开题答辩全过程】以 校园帮帮团跑腿系统的设计与实现为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

Milvus 向量数据库开发实战指南

Milvus向量数据库是什么&#xff1f;-CSDN博客 一、核心概念解析 1.1 基础概念 1.1.1 Bitset&#xff08;位集&#xff09; 高效的数据表示方式&#xff0c;使用位数组替代传统数据类型 默认情况下&#xff0c;位值根据特定条件设置为 0 或 1 1.1.2 通道机制 PChannel&am…

vcruntime140.dll丢失解决办法

解决办法 安装Microsoft Visual C Redistributable https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?viewmsvc-170