Redis Lua 脚本核心语法详解:KEYS[1]、ARGV[1]、tonumber 是什么意思?

文章目录

在使用 Redis Lua 脚本时,你几乎一定会看到下面这些写法:

lua 复制代码
redis.call('get', KEYS[1])
local num = tonumber(ARGV[1])

很多人在第一次接触 Lua + Redis 时都会有疑问:

  • KEYS[1] 是什么?为什么从 1 开始?
  • ARGV[1] 又是什么?和 KEYS 有什么区别?
  • tonumber 为什么几乎"必写"?
  • 这些东西在 Java 里是怎么传进来的?

一、Redis Lua 脚本的参数模型

在 Redis 中,Lua 脚本的参数只有两类

text 复制代码
KEYS  ------ 存 Redis key
ARGV  ------ 存普通参数

Lua 脚本本身 不能直接接收任意参数

Redis 强制你把参数分成这两组。


Redis 执行 Lua 的基本语法

redis 复制代码
EVAL <lua-script> <numkeys> <key1> <key2> ... <arg1> <arg2> ...

例如:

redis 复制代码
EVAL "return {KEYS[1], ARGV[1]}" 1 product:stock:1 5

二、KEYS1 是什么意思?

1、KEYS 是什么?

KEYS 是 Redis 传给 Lua 的"Key 数组"

lua 复制代码
KEYS = { key1, key2, key3, ... }

2、为什么是 KEYS1,而不是 KEYS0

因为 Lua 数组下标从 1 开始

lua 复制代码
KEYS[1]  -- 第一个 key
KEYS[2]  -- 第二个 key

👉 这是 Lua 语言的规则,不是 Redis 的设计失误。


3、KEYS1 在脚本中的真实含义

lua 复制代码
redis.call('get', KEYS[1])

等价于:

从 Redis 中获取第一个传入的 key 对应的值


示例:库存 key

redis 复制代码
EVAL "return redis.call('get', KEYS[1])" 1 product:stock:1

Lua 中:

lua 复制代码
KEYS[1] == "product:stock:1"

5、为什么 Redis 强制区分 KEYS?

原因只有一个:

安全 + 集群路由

  • Redis Cluster 需要提前知道哪些是 key
  • 才能把脚本路由到正确的节点
  • 如果 key 混在普通参数里,Redis 无法判断

👉 所以:Redis 规定 key 必须放在 KEYS 里


三、ARGV1 是什么意思?

ARGV 是什么?

ARGV 是 Redis 传给 Lua 的"普通参数数组"

lua 复制代码
ARGV = { arg1, arg2, arg3, ... }

ARGV 和 KEYS 的核心区别

对比项 KEYS ARGV
是否 Redis key ✅ 是 ❌ 否
是否参与路由 ✅ 是 ❌ 否
用途 get / set / decr 数量、阈值、参数

示例:扣减库存数量

redis 复制代码
EVAL "return ARGV[1]" 1 product:stock:1 3

Lua 中:

lua 复制代码
ARGV[1] == "3"

👉 注意:ARGV 永远是字符串


四、tonumber 是什么意思?为什么一定要用?

tonumber 是 Lua 的类型转换函数

lua 复制代码
tonumber("10")   --> 10
tonumber(nil)    --> nil

为什么 ARGV 一定要 tonumber?

因为:

Redis 传给 Lua 的所有参数,本质上都是字符串

例如:

lua 复制代码
ARGV[1] == "3"

如果你直接做数学运算:

lua 复制代码
if ARGV[1] <= 0 then   -- ❌ 错误

Lua 会直接报错。


正确写法(必须)

lua 复制代码
local num = tonumber(ARGV[1])

if num <= 0 then
    return -1
end

tonumber + redis.call 的经典组合

lua 复制代码
local stock = tonumber(redis.call('get', KEYS[1]))

含义是:

把 Redis 中存的字符串库存,转换成 Lua 可计算的数字


五、三个概念放在一起的完整示例(库存脚本)

lua 复制代码
-- KEYS[1] : 库存 key
-- ARGV[1] : 扣减数量

local stock = tonumber(redis.call('get', KEYS[1]))
local num = tonumber(ARGV[1])

-- 库存不存在
if not stock then
    return -2
end

-- 库存不足
if stock < num then
    return -1
end

redis.call('decrby', KEYS[1], num)
return stock - num

对应的 Redis 调用

redis 复制代码
EVAL "<lua-script>" 1 product:stock:1 2

对应的 Java 调用(Spring Boot)

java 复制代码
redisTemplate.execute(
    script,
    Collections.singletonList("product:stock:1"),
    2
);

六、常见误区总结(你很可能踩过)

❌ 误区 1:KEYS 和 ARGV 随便用

👉 key 一定放 KEYS


❌ 误区 2:不写 tonumber

lua 复制代码
if ARGV[1] > 0 then  -- ❌

👉 字符串不能直接比较


❌ 误区 3:用 KEYS 传普通参数

lua 复制代码
KEYS[1] = "3"  -- ❌

👉 会破坏 Redis Cluster 路由


七、总结

  • KEYS[1]:Lua 脚本中第一个 Redis key
  • ARGV[1]:Lua 脚本中第一个普通参数
  • tonumber:把 Redis / ARGV 的字符串转换成数字

这三个概念,是 Redis Lua 脚本的入门三板斧

相关推荐
IT大白鼠2 天前
Redis 系列 · 第 01 篇——认知入门:Redis 是什么
redis·nosql
彧azz2 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
lbb 小魔仙2 天前
OpenClaw + cpolar 实战:远程 NAS、分享小游戏、RDP,再配置公网 AI 入口
数据库·人工智能·redis·oracle·prometheus
夕除2 天前
redis--018
redis
两锭子2 天前
Redis基础
redis
烟沙九洲2 天前
Redis 缓存穿透、缓存击穿、缓存雪崩
数据库·redis
字节探索2 天前
Redis 只会当缓存用?这 10 大实战场景,让你的系统快到飞起
redis·后端
于樱花森上飞舞2 天前
【Redis】哨兵详解
java·开发语言·数据库·redis
Rain的Java大神之路2 天前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
Wang's Blog2 天前
Java 接入Redis: 通用命令与键管理
java·服务器·redis