Redis的Lua脚本
2026年2月24日大约 3 分钟
Redis的Lua脚本
Redis提供了Lua脚本功能,可以在Lua脚本中编写多条Redis命令,确保这些命令执行的原子性。
提示
这里就不再对Lua脚本的语法进行介绍,具体语法请自行查阅官方文档。
Lua脚本调用Redis
首先肯定是要先编写一个Lua脚本的文件。
- 获取参数
提示
在Redis Lua脚本中,KEYS和ARGV是两个特殊的全局变量,用于获取传递给脚本的参数。
KEYS:用于获取传递给脚本的键参数,索引从1开始。ARGV:用于获取传递给脚本的其他参数,索引同样从1开始。- 注意这两个参数都是Redis 特有的预定义全局变量,不是 Lua 语言本身的一部分。
local key1 = KEYS[1]
local arg1 = ARGV[1]- 执行Redis命令
redis.call('命令', key1, arg1)Redis执行Lua脚本
通过EVAL命令来执行Lua脚本,语法如下:
EVAL script numkeys key [key ...] arg [arg ...]script:要执行的Lua脚本内容,可以直接写在命令中,也可以是一个Lua脚本文件的内容。numkeys:指定传递给脚本的键参数的数量。key [key ...]:传递给脚本的键参数,数量由numkeys指定。arg [arg ...]:传递给脚本的其他参数,可以是任意数量的参数。
示例:
EVAL "return redis.call('GET', KEYS[1])" 1 mykey需要先传key,因为前面指定了key数量,后面的就都是arg了。
解决分布式锁的原子性问题-Lua脚本
业务流程:
- 获取Redis存入的线程标识。
- 判断线程标识是否和当前线程的标识相同。
- 如果相同则删除锁,否则不做任何操作。
-- 获取存入的线程标识
local id = redis.call('GET', KEYS[1])
-- 获取当前线程的标识
local currentId = ARGV[1]
-- 判断线程标识是否相同
if (id == currentId) then
-- 如果相同则删除锁
return redis.call('DEL', KEYS[1])
end
return 0写完Lua脚本后,下面就需要在Java中调用了。
Java调用Lua脚本
- 使用RedisTemplate的
execute方法来执行Lua脚本。 - 前置准备:将Lua脚本文件放在Resources目录下。
- 静态加载Lua脚本文件
private static final DefaultRedisScript<Long> UNLOCK_SCRIPT; static { UNLOCK_SCRIPT = new DefaultRedisScript<>(); UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua")); UNLOCK_SCRIPT.setResultType(Long.class); } - 调用Lua脚本
stringRedisTemplate.execute( UNLOCK_SCRIPT, Collections.singletonList(KEY_PREFIX + name), ID_PREFIX + Thread.currentThread().getId());
- 这里的
execute方法的参数说明: script:要执行的Lua脚本,可以是一个字符串,也可以是一个DefaultRedisScript对象。keys:传递给Lua脚本的键参数,数量由Lua脚本中的KEYS变量指定。args:传递给Lua脚本的其他参数,数量由Lua脚本中的ARGV变量指定。
setnx实现的分布式锁存在的问题

图:基于setnx实现的分布式锁存在的问题
为了解决这些问题,我们可以使用Redisson来实现分布式锁。