lua脚本介绍与使用 中文官网
从Redis2.6.0版本开始,通过内置的Lua解释器,可以使用EVAL命令对Lua脚本进行求值
lua脚本在redis中的使用
1.特性
Redis保证脚本以原子性方式执行。当脚本被执行时,不会有其他脚本或者redis命令执行。
2.优势
在redis官方文档中管道的介绍中有提到
大量 pipeline 应用场景可通过 Redis 脚本(Redis 版本 >= 2.6)得到更高效的处理,后者在服务器端执行大量工作。脚本的一大优势是可通过最小的延迟读写数据,让读、计算、写等操作变得非常快(pipeline 在这种情况下不能使用,因为客户端在写命令前需要读命令返回的结果)。
3.使用
eval script numkeys key [key ...] arg [arg ...]
第一个参数是lua5.1脚本,第二个参数是[key...]参数的个数,第三个参数是lua脚本中的KEYS[n],第四个参数是lua脚本中的ARGV[m]
eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
在lua脚本中使用redis.call()/redis.pcall() 执行redis命令
eval "return redis.call('set',KEYS[1],'bar')" 1 foo
4.注意
redis将所有的输入参数都设为了string类型,所以,在执行与ARVG[1]的比较前,需要显式地调用Lua的tonumber()内建函数将ARGV[1]转化为number类型
redisTemplate操作lua脚本
一个简单的访问频率的限制脚本 limit.lua
local times = redis.call('incr',KEYS[1])
if times == 1 then
redis.call('expire',KEYS[1],ARGV[1])
end
if times > tonumber(ARGV[2]) then
return 'a'
end
return 'b'
使用Resource获取资源
DefaultRedisScript redisScript = new DefaultRedisScript();
//放在和application.yml 同层目录下
redisScript.setLocation(new ClassPathResource("limit.lua"));
redisScript.setResultType(String.class);
List<String> list = new ArrayList<>();
list.add("door");
//定义 keys,argv和result序列化方式
//控制每60秒的访问频率为5次
Object result = redisTemplate.execute(redisScript,new StringRedisSerializer(),new StringRedisSerializer(),list,"60","5");
使用lua脚本字符串
RedisScript redisScript = RedisScript.of("local times = redis.call('incr',KEYS[1]) if times == 1 then redis.call('expire',KEYS[1],ARGV[1]) end if times > tonumber(ARGV[2]) then return 0 end return 1",
Long.class);//注意是Long类型,而不是Integer
List<String> list = new ArrayList<>();
list.add("door3");
Object result = redisTemplate.execute(redisScript,new StringRedisSerializer(),new StringRedisSerializer(),list,"60","5");
注意:
1.RedisScript的resultType的选择(result值类型)
2.RedisSerializer()的选择(keys,args,result值的序列化规则)
参考:《redis入门指南》第二版 第六章
spring data redis 官方文档 - Redis Scripting的介绍