使用 RedisTemplate 执行 lua 脚本时结果令人困惑

Posted

技术标签:

【中文标题】使用 RedisTemplate 执行 lua 脚本时结果令人困惑【英文标题】:Confusing result when using RedisTemplate to execute lua scripts 【发布时间】:2019-03-03 08:43:23 【问题描述】:

我正在使用 spring-boot-starter-data-redis 2.0.5.RELEASE。我用 RestTemplate 执行一个 lua 脚本。 脚本:

-- hold.lua
if redis.call('get', KEYS[1]) == ARGV[1] then
    redis.call('pexpire', KEYS[1], ARGV[2])
    return 1
end
return 0

Java 代码:

@Override
public void executeHold(String lockKey, String lockValue, long expireInMillis) 
    DefaultRedisScript<Boolean> holdScript = new DefaultRedisScript<>();
    holdScript.setLocation(new ClassPathResource("lua/hold.lua"));
    holdScript.setResultType(Boolean.class);
    // CODE 1
    Boolean result = redisTemplate.execute(holdScript, Collections.singletonList(lockKey), lockValue, expireInMillis);
    // END of CODE 1
    //        // CODE 2
    //        String script = holdScript.getScriptAsString();
    //        Boolean result = redisTemplate.execute(new RedisCallback<Boolean>() 
    //            @Override
    //            public Boolean doInRedis(RedisConnection connection) throws DataAccessException 
    //                return connection.scriptingCommands()
    //                        .eval(
    //                                script.getBytes(),
    //                                ReturnType.fromJavaType(Boolean.class),
    //                                1,
    //                                lockKey.getBytes(),
    //                                lockValue.getBytes(),
    //                                String.valueOf(expireInMillis).getBytes()
    //                        );
    //            
    //        );
    //        // END of CODE 2
    System.out.println(holdScript.getSha1());
    LOGGER.debug("Execute holdScript, result=, content=\n", result, holdScript.getScriptAsString());

我在redis中设置了lockKey

127.0.0.1:6379> set lockKey lockValue PX 600000 NX

当我使用CODE 1 运行上面的代码时,我总是得到result = false

但是当我更改上面的代码时,使用CODE 2,我可以得到预期的正确结果。

这真的让我很困惑,有人可以帮我找出问题所在吗?谢谢。

我想做的是Here。

【问题讨论】:

在setLocation之前,你能'setScriptSource'吗?好像没有加载脚本 @wsha 看了源码,setLocation和setScriptSource一样。对不起,我找到了真正的原因,它只是由redisTemplate.execute()方法引起的,看起来它总是给我一个错误的结果,但我不知道为什么......我已经编辑了问题,你能再试一次吗,谢谢! 【参考方案1】:

我遇到了类似的问题。我的问题的根本原因是我在我的 redis 模板中使用了 json 序列化程序,它在我传递给脚本的字符串值中添加了额外的引号。将序列化程序更改为字符串序列化程序解决了我的问题。

【讨论】:

以上是关于使用 RedisTemplate 执行 lua 脚本时结果令人困惑的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot通过RedisTemplate执行Lua脚本

springboot redis 用RedisTemplate执行lua脚本报错:@user_script:1: ERR value is not an integer or out of range

使用RedisTemplate+Lua脚本实现Redis分布式锁

redis的lua脚本快速入门

redis原子性读写操作

lua 变量