Redis 使用lua脚本最全教程

Redis 使用lua脚本最全教程1 redis 使用 lua 脚本的语法 RedisEval 命令 执行 Lua 脚本 redis127 0 0 1 6379 gt eval return KEYS 1 KEYS 2 ARGV 1 ARGV 2 2key1key2fir key1 2 key2 3 first 4 second 其中 script 参数是一段 Lua5 1 脚本程序 脚本不必 也不应该 定义为一个 Lua 函数 numkeys 用于指定键名

收录于墨的2020~2021开发经验总结

1、redis 使用lua脚本的语法

Redis Eval 命令 – 执行 Lua 脚本

redis 127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second 1) "key1" 2) "key2" 3) "first" 4) "second" 

可以直接通过 redis-cli –eval执行写好的lua脚本:

redis-cli --eval /test.lua 0 

2、Lua

lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

下载

print('hello world') -- 注释 a=1 b="abc" c={ 
   } d=print c={ 
   "a","b","c"} print(type(a)) print(type(b)) print(type(c)) print(type(d)) -- 多行注释 [[ -------- Output ------ number string table function ]] a="single 'quoted' string and double \"quoted\" string inside" b='single \'quoted\' string and double "quoted" string inside' c= [[ multiple line with 'single' and "double" quoted strings inside.]] print(a) print(b) print(c) [[ -------- Output ------ single 'quoted' string and double "quoted" string inside single 'quoted' string and double "quoted" string inside multiple line with 'single' and "double" quoted strings inside. ]] a,b,c,d,e = 1, 2, "three", "four", 5 a,b,c,d,e = 1, 1.123, 1E9, -123, .0008 print("a="..a, "b="..b, "c="..c, "d="..d, "e="..e) [[ -------- Output ------ a=1 b=1.123 c= d=-123 e=0.0008 ]] address={ 
   } -- empty address address.Street="Wyman Street" address.StreetNumber=360 address.AptNumber="2a" address.City="Watertown" address.State="Vermont" address.Country="USA" print(address.StreetNumber, address["AptNumber"]) -- end 结束 a=1 if a==1 then print ("a is one") end c=3 if c==1 then print("c is 1") elseif c==2 then print("c is 2") else print("c isn't 1 or 2, c is "..tostring(c)) end a=1 b=(a==1) and "one" or "not one" print(b) -- b = ((a==1) ? "one" : "not one") -- 循环 a=1 while a~=5 do -- Lua uses ~= to mean not equal a=a+1 io.write(a.." ") end a=0 repeat a=a+1 print(a) until a==5 for a=1,6,3 do io.write(a) end -- 14 [[ for (int i = 1; i < 6; i += 3) { printf(i); } ]] for key,value in pairs({ 
   1,2,3,4}) do print(key, value) end [[ -------- Output ------ 1 1 2 2 3 3 4 4 ]] a={ 
   1,2,3,4,"five","elephant", "mouse"} for i,v in pairs(a) do print(i,v) end [[ -------- Output ------ 1 1 2 2 3 3 4 4 5 five 6 elephant 7 mouse ]] -- break a=0 while true do a=a+1 if a==10 then break end end -- 函数 function myFirstLuaFunctionWithMultipleReturnValues(a,b,c) return a,b,c,"My first lua function with multiple return values", 1, true end a,b,c,d,e,f = myFirstLuaFunctionWithMultipleReturnValues(1,2,"three") print(a,b,c,d,e,f) [[ -------- Output ------ 1 2 three My first lua function with multiple return values 1 true ]] -- local 局部变量 function myfunc() local b=" local variable" a="global variable" print(a,b) end function printf(fmt, ...) io.write(string.format(fmt, ...)) end printf("Hello %s from %s on %s\n", os.getenv"USER" or "there", _VERSION, os.date()) -- Math functions: -- math.abs, math.acos, math.asin, math.atan, math.atan2, -- math.ceil, math.cos, math.cosh, math.deg, math.exp, math.floor, -- math.fmod, math.frexp, math.huge, math.ldexp, math.log, math.log10, -- math.max, math.min, math.modf, math.pi, math.pow, math.rad, -- math.random, math.randomseed, math.sin, math.sinh, math.sqrt, -- math.tan, math.tanh -- String functions: -- string.byte, string.char, string.dump, string.find, string.format, -- string.gfind, string.gsub, string.len, string.lower, string.match, -- string.rep, string.reverse, string.sub, string.upper -- Table functions: -- table.concat, table.insert, table.maxn, table.remove, table.sort -- IO functions: -- io.close , io.flush, io.input, io.lines, io.open, io.output, io.popen, -- io.read, io.stderr, io.stdin, io.stdout, io.tmpfile, io.type, io.write, -- file:close, file:flush, file:lines ,file:read, -- file:seek, file:setvbuf, file:write print(io.open("file doesn't exist", "r")) -- OS functions: -- os.clock, os.date, os.difftime, os.execute, os.exit, os.getenv, -- os.remove, os.rename, os.setlocale, os.time, os.tmpname -- require导入包 require( "iuplua" ) ml = iup.multiline { 
    expand="YES", value="Quit this multiline edit app to continue Tutorial!", border="YES" } dlg = iup.dialog{ 
   ml; title="IupMultiline", size="QUARTERxQUARTER",} dlg:show() print("Exit GUI app to continue!") iup.MainLoop() 

Lua 运行了一个垃圾收集器来收集所有死对象 (即在 Lua 中不可能再访问到的对象)来完成自动内存管理的工作。 Lua 中所有用到的内存,如:字符串、表、用户数据、函数、线程、 内部结构等,都服从自动管理。

Lua 实现了一个增量标记-扫描收集器。 它使用这两个数字来控制垃圾收集循环: 垃圾收集器间歇率和垃圾收集器步进倍率。 这两个数字都使用百分数为单位 (例如:值 100 在内部表示 1 )。

3、redis使用Lua

通过return 返回结果,通过redis.call执行redis命令:

eval "return redis.call('keys','*')" 0 

以上命令返回所有的key,类似于直接执行 keys *

以下命令删除dict*格式的所有key值

eval "local redisKeys = redis.call('keys',KEYS[1]..'*');for i,k in pairs(redisKeys) do redis.call('del',k);end;return redisKeys;" 1 dict 

展开如下

local redisKeys = redis.call('keys',KEYS[1]..'*'); for i,k in pairs(redisKeys) do redis.call('del',k); end; return redisKeys; 

以下命令删除所有key值

eval "local sum = 0;for i,k in pairs(redis.call('keys','*')) do redis.call('del', k);sum=sum+1;end; return 'clear '..sum..' key'" 0 

批量生产key值,设置过期时间,参数: 2、 key个数、 key前缀、 key的值、 key的过期时间(可选)

 eval "for i=1,KEYS[1],1 do local k=KEYS[2]..i; redis.call('set',k,ARGV[1]);if ARGV[2] then redis.call('expire',k,ARGV[2]) end;end;return redis.call('keys',KEYS[2]..'*');" 2 10 test 0 20 

在这里插入图片描述

删除所有值为0的key,参数:0、值X

 eval "local ks = {};for i,k in pairs(redis.call('keys','*')) do local v = redis.call('get',k);if v==ARGV[1] then redis.call('del',k);table.insert(ks,k); end;end;return ks;" 0 0 

删除所有永不过期的key

 eval "local ks = {};for i,k in pairs(redis.call('keys','*')) do local ttl = redis.call('ttl',k);if ttl==-1 then redis.call('del',k);table.insert(ks,k); end;end;return ks;" 0 

获取所有值为0,并以test为前缀的key列表,参数:2、x、y

 eval "local ks = {};for i,k in pairs(redis.call('keys',KEYS[1]..'*')) do local v = redis.call('get',k);if v==ARGV[1] then table.insert(ks,k); end;end;return ks;" 1 test 0 

redis分布式锁实现,之加锁。如果不存在lock,则设置local233,并设置过期时间为60,如果返回1表示加锁成功,返回0则加锁失败,该操作是原子操作,可以由等效命令 set lock 233 nx ex 60代替:

eval "if redis.call('get',KEYS[1]) then return 0;else redis.call('set',KEYS[1],ARGV[1]);redis.call('expire',KEYS[1],ARGV[2]);return 1;end;" 1 lock 233 60 

展开如下

if redis.call('get',KEYS[1]) then return 0; else redis.call('set',KEYS[1],ARGV[1]); redis.call('expire',KEYS[1],ARGV[2]); return 1; end 

redis分布式锁实现,之释放锁。如果不存在lock,则无需释放,如果存在lock并且值和传入的值一致,那么删除lock,释放成功,其他情况返回释放失败。成功:1,失败0。

eval "local v = redis.call('get',KEYS[1]);if v then if v~=ARGV[1] then return 0;end;redis.call('del',KEYS[1]);end;return 1;" 1 lock 233 

展开如下

local v = redis.call('get',KEYS[1]); if v then -- 如果和传入的值不同,返回0表示失败 if v~=ARGV[1] then return 0; end; -- 删除key redis.call('del',KEYS[1]); end; return 1; 

4、redisTemplate执行脚本的方法封装

 @Component public class RedisUtil { 
    @Resource private RedisTemplate<String, Object> redisTemplate; / * 执行 lua 脚本 * @author hengyumo * @since 2021-06-05 * * @param luaScript lua 脚本 * @param returnType 返回的结构类型 * @param keys KEYS * @param argv ARGV * @param <T> 泛型 * * @return 执行的结果 */ public <T> T executeLuaScript(String luaScript, Class<T> returnType, String[] keys, String... argv) { 
    return redisTemplate.execute(RedisScript.of(luaScript, returnType), new StringRedisSerializer(), new GenericToStringSerializer<>(returnType), Arrays.asList(keys), (Object[])argv); } } 

使用很简单,以下用上边使用过的两个脚本作为示例:

 @Resource private RedisUtil redisUtil; @Test @SuppressWarnings("unchecked") public void testExecuteLuaScript() { 
    String script = "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}"; List<Object> list = (List<Object>)redisUtil.executeLuaScript(script, List.class, new String[] { 
   "a", "b"}, "a", "b"); list.forEach(x -> System.out.println(x.toString())); script = "for i=1,KEYS[1],1 do local k=KEYS[2]..i; redis.call('set',k,ARGV[1]);" + "if ARGV[2] then redis.call('expire',k,ARGV[2]) end;end;" + "return redis.call('keys',KEYS[2]..'*');"; list = (List<Object>)redisUtil.executeLuaScript(script, List.class, new String[] { 
   "10", "test"}, "0", "60"); list.forEach(x -> System.out.println(x.toString())); } 

输出结果,返回的结果是List<List>:

[a] [b] [a] [b] [test1] [test10] [test2] [test3] [test4] [test5] [test6] [test7] [test8] [test9] 

封装方法:删除以key为前缀的所有键值

 // 以下命令删除xxx*格式的所有key值 private final static String LUA_SCRIPT_CLEAR_WITH_KEY_PRE = "local redisKeys = redis.call('keys',KEYS[1]..'*');" + "for i,k in pairs(redisKeys) do redis.call('del',k);end;" + "return redisKeys;"; / * @author hengyumo * @since 2021-06-05 * * 删除以key为前缀的所有键值 * @param keyPre 前缀 * @return 返回删除掉的所有key */ public List<String> deleteKeysWithPre(String keyPre) { 
    @SuppressWarnings("unchecked") List<Object> result = executeLuaScript(LUA_SCRIPT_CLEAR_WITH_KEY_PRE, List.class, new String[] { 
   keyPre}); return result.stream().map(x -> { 
    if (x instanceof List) { 
    @SuppressWarnings("unchecked") List<String> list = (List<String>) x; if (list.size() > 0) { 
    return list.get(0); } } return null; }).filter(Objects::nonNull).collect(Collectors.toList()); } 

使用很简单:

 @Test public void testDeleteKeysWithPre() { 
    List<String> list = redisUtil.deleteKeysWithPre("DAWN"); list.forEach(System.out::println); } 

END

写作不易,您的小小一个?会让我更加有动力。


那在终点之前,我愿意再爱一遍。 ——墨

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/231615.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 上帝掷骰子吗–量子物理史话

    上帝掷骰子吗–量子物理史话  上帝掷骰子吗–量子物理史话    第一章黄金时代    一    我们的故事要从1887年的德国开始。位于莱茵河边的卡尔斯鲁厄是一座风景秀丽的城市,在它的城中心,矗立着著名的18世纪的宫殿。郁郁葱葱的森林和温暖的气候也使得这座小城成为了欧洲的一个旅游名胜。然而这些怡人的景色似乎没有分散海因里希?鲁道夫?赫兹(HeinrichRudolfHertz)的注意力:现在他正

    2022年6月7日
    35
  • laravel框架中使用QueryList插件采集数据

    laravel框架中使用QueryList插件采集数据

    2021年10月31日
    43
  • 决策树—回归[通俗易懂]

    决策树—回归[通俗易懂]核心:划分点选择+输出值确定。一、概述决策树是一种基本的分类与回归方法,本文叙述的是回归部分。回归决策树主要指CART(classificationandregressiontree)算法,内部结点特征的取值为“是”和“否”,为二叉树结构。所谓回归,就是根据特征向量来决定对应的输出值。回归树就是将特征空间划分成若干单元,每一个划分单元有一个特定的输出。因为每个结点都是“是”…

    2022年8月21日
    11
  • svn中文语言包安装无反应_英文版win7安装语言包

    svn中文语言包安装无反应_英文版win7安装语言包1.中文语言包下载地址,两种下载方式:下载(1.9.4版本):https://sourceforge.net/projects/tortoisesvn/files/1.9.4/Language%20Packs/官网下载:https://tortoisesvn.net/downlo…

    2025年7月6日
    2
  • Error: org.apache.axis2.AxisFault at org.apache.axis2.AxisFault.makeFault(AxisFault.java:430) at 的原因

    Error: org.apache.axis2.AxisFault at org.apache.axis2.AxisFault.makeFault(AxisFault.java:430) at 的原因Error:org.apache.axis2.AxisFaultatorg.apache.axis2.AxisFault.makeFault(AxisFault.java:430)atorg.apache.axis2.description.AxisService.createService(AxisService.java:2504)atorg.apache.axis2.des

    2025年9月5日
    4
  • LaTeX详细安装步骤和简明教程

    LaTeX详细安装步骤和简明教程第一步:环境配置配置TeXLive和TeXstudio。TeXLive是编译器为Latex提供运行所需的环境;TeXstudio编辑器,提供操作界面,需要先安装好TeXLive之后,TeXstudio才能使用。TeXLive下载:TeXLive下载地址:(清华镜像)https://mirrors.tuna.tsinghua.edu.cn/ctan/systems/texlive/Images/下载“.iso”文件–>“texlive2020.iso3.7GiB…

    2022年5月18日
    58

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号