Lua脚本执行redis指令报错【java.lang.IllegalStateException】
-
问题出现背景
今天在学习redis时,为了让redis的多条指令(取锁、比锁、释放锁)保障原子性,我通过使用一个lua脚本统一去执行redis的的多条指令。在执行lua脚本时报错
-
问题说明
-
问题复现
这是我的lua脚本-- 获取锁的key,即: KEY_PREFIX + name local key = KEYS[1] -- 获取当前线程的标识, 即: ID_PREFIX + Thread.currentThread().getId() local threadId = ARGV[1] -- 获取锁中的线程标识, 对应的redis指令为: get key local id = redis.call('get', key) -- 判断缓存中的锁是否是当前线程的锁 if(threadId == id) then -- 缓存中的锁是当前线程的锁,释放锁 del key return redis.call('del', key) end -- 缓存中的锁不是当前线程的锁,啥都不干 return 0
java代码
public void unlock(){ // 获取keys。execute可以接收多个key,它的参数类型是List,所以这里需要先转成List集合 List<String> keys = Collections.singletonList(this.key); DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); // 调用lua脚本,通过lua脚本执行redis命令来释放锁 stringRedisTemplate.execute(redisScript , keys, this.value); }
备注:
key
是当前缓存中的分布式锁对应的key,value
是当前线程的锁对应的值 -
问题结果过程
我根据报错信息,显示排查是不是我的Lua脚本写错了,但是我确定并不是我的Lua脚本报错,于是我就将重心放在Java代码上,于是就搜索了一下,发了这个博主出现了和我类似的问题,https://blog.csdn.net/tengdazhang770960436/article/details/95653977,我就抱着试一试的态度设置了脚本执行后的返回结果的数据类型,结果就成功了。但是我仍然有疑问:我不是在创建脚本对象时,已经设置过泛型了吗?怎么还需要显示地指明脚本的返回值的数据类型?而且我在看Redis教程时,那个老师也没有设置返回值类型,这一点我就有点懵了😫
只需要在执行脚本前添加一行redisScript.setReasultType(Long.class);
就成功解决了这个问题
老师的代码,也是只指明泛型,然后就直接执行脚本,并没有指明脚本执行后返回值的类型啊?
-
问题出现的原因
由于笔者实力较菜,目前还不能够明确为什么一定需要设置脚本的返回值类型才能让。我的猜测是可能由于我的Redis版本和老师的不太一样导致的,因为我用的是最新版的Redis6.x,而老师使用的是Redis5.x。如果有大佬知道原因,恳请留言或私信我,让我能够解惑,在下不胜感激