前言
redis作为一种key-value的缓存中间件,支持字符串,哈希,集合,有序集合等结构,每种结构都只支持比较简单的命令,这就决定了redis自身不支持复杂的业务运算,但redis支持lua脚本,可以通过lua脚本原子性地完成一些复杂的业务逻辑。
java中运行lua脚本
java中运行lua脚本比较简单,如下
public <T> T runLua(String fileClasspath, Class<T> returnType, List<String> keys, Object ... values){ DefaultRedisScript<T> redisScript =new DefaultRedisScript<>(); redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource(fileClasspath))); redisScript.setResultType(returnType); return redisTemplate.execute(redisScript,keys,values); }
第一个参数是lua脚本的路径,一般lua脚本写成文件的形式比较合适。
第二个参数是返回类型,返回类型一般是string或者list类型。
第三个参数是key列表,如果在Cluster集群中,列表中的key如果分布在不同的节点上会出错,为了避免这个问题,需要在同一节点的keys都加上标志,如key1{me},key2{me}
第四个参数是参数列表。
lua脚本
lua脚本是如何获取入参的,它是通过KEYS[1],ARGV[1]....下标从1开始。
那么又是如果返回结果的,它是通过return语法返回的,一般是字符串或者table类型,table对应java中的list类型。
可以看看下面脚本,逻辑比较简单,遍历key中的所有值,返回符合条件的列表。
local result={}; local key=KEYS[1]; local value=ARGV[1]; local list =redis.call("hkeys",key); for i,v in ipairs(list) do local val= redis.call("hget",key,v); if(tonumber(val)<tonumber(value)) then table.insert(result,1,v); end end return result;
redis命令
从上面的脚本可以看到,lua脚本里面是通过redis.call("command",key,argv.....)的形式执行redis命令的,而命令繁多,这里不一一叙述,可以看教程 https://www.runoob.com/redis/redis-commands.html
lua语法
lua也有自身的语法和数据类型,具体可以看 https://www.runoob.com/lua/lua-basic-syntax.html
小结
lua脚本使用上比较简单,但是要注意性能,不能执行太复杂的运算,在redis中的操作都是单线程的,如果执行太慢,会阻塞其他请求的,如果在lua中写一个死循环,那就完了。