LUA脚本

张开发
2026/6/9 21:48:24 15 分钟阅读
LUA脚本
目录一、Lua脚本1.编写脚本2.调用脚本3.Lua实现可重入锁3.1 获取锁3.2 释放锁二、Redis事务一、Lua脚本Lua脚本中可以编写多条Redis命令确保多条命令共同执行时是一个原子操作但不保证原子性同时成功同时失败中间运行出错不会回滚出错位置之后的命令不会执行 。1.编写脚本Lua执行redis命令的语法redis.call(命令名称, key, 其它参数,...)-- 释放锁的lua脚本-- 锁的keylocalkeyKEYS[1]-- 当前线程标识localthreadIdARGV[1]-- 获取锁中的线程标识localidredis.call(get,key)-- 比较线程标识与锁中的标识是否一致if(idthreadId)then-- 释放锁returnredis.call(del,key)endreturn02.调用脚本语法EVAL 脚本内容字符串 参数数量 key [key...] arg [arg...]脚本中的key、value可以作为参数传递key类型参数会放入KEYS数组其它参数会放入ARGV数组使用数组下标取值默认下标从1开始。// 不加参数无形参EVALreturn redis.call(set, name, jack)0// 加参数EVALreturn redis.call(set, KEYS[1], ARGV[1])1name jackStringRedisTemplate调用Lua脚本的API如下// 调用lua脚本释放锁publicvoidunlock1(Stringname){// RedisScript是一个脚本类用来接收lua脚本文件DefaultRedisScriptLongunlock_scriptnewDefaultRedisScript();// ClassPath默认是resources文件夹设置lua脚本文件位置unlock_script.setLocation(newClassPathResource(unlock.lua));// 设置lua脚本的返回值unlock_script.setResultType(Long.class);// 调用lua脚本注意KEYS传的是List集合stringRedisTemplate.execute(unlock_script,Collections.singletonList(lock:name),String.valueOf(Thread.currentThread().getId()));}3.Lua实现可重入锁3.1 获取锁localkeyKEYS[1];--锁的key,一人一单问题就是用户id,同一用户的多个线程竞争同一把锁localthreadIdARGV[1];--持有锁的线程标识localreleaseTimeARGV[2];--锁的有效期--锁是未被占有if(redis.call(exists,key)0)thenredis.call(hset,key,theadId,1);--获取锁redis.call(expire,key,releaseTime);--设置有效期return1;--返回表示获取成功end;--锁已被占有,且锁是本线程占有的if(redis.call(hexists,key,threadId)1)thenredis.call(hincrby,key,threadId,1);--重入计数自增1redis.call(expire,key,releaseTime);--重置有效期return1;end;--锁已被占有且不是本线程占有的return0;3.2 释放锁localkeyKEYS[1];--锁的key,一人一单问题就是用户id同一用户的多个线程竞争同一把锁localthreadIdARGV[1];--持有锁的线程标识localreleaseTimeARGV[2];--锁的有效期--当前锁不是被本线程持有if(redis.call(hexists,key,threadId)0)thenreturnnil;end;--当前所被本线程持有localcountredis.call(hincrby,key,threadId,-1);--可重入次数-1--可重入次数是否减为0if(count0)thenredis.call(‘expire’,key,releaseTime)--重置有效期returnnil;elseredis.call(del,key)end;returnnil;二、Redis事务redis事务和lua脚本在执行期间会阻塞其他redis请求且中间执行失败都不能回滚。redis事务需要多次网络i/olua进需要一次网络i/o。如果执行期间出现运行时错误redis事务会继续执行lua会放弃执行后续命令。redis事务无法使用if等控制流。#1.开启事务 MULTI#2.入队命令不会立即执行返回 QUEUED SET name 张三 GET name INCR count#3.执行事务一次性执行所有命令 EXEC

更多文章