使用 RedisTemplate 执行 Lua 脚本永远不起作用
Posted
技术标签:
【中文标题】使用 RedisTemplate 执行 Lua 脚本永远不起作用【英文标题】:Executing Lua Script with RedisTemplate never works 【发布时间】:2020-11-04 05:47:57 【问题描述】:我目前正在为 kafka 和 GC PubSub 开发基准工具。我想查看关于 min 的结果。最大和平均传输速度。在之前,我将每个条目设置为 reddis 哈希。之后,我将 reddis 哈希映射到 java map 并在进程结束时对它们进行迭代以获取最小值、最大值。它看起来很慢,因为如果我调用 100000 条目,程序会迭代 x3 的最小值、最大值和平均值。所以我尝试使用 Lua 脚本来做到这一点。发布消息后,我设置了哈希映射的开始时间,当侦听器收到消息时,我从哈希中获取消息的开始时间,并计算与System.currentTimeMillis
的差异。在这一步之后,我尝试执行 Lua 脚本,将当前值与旧值进行比较并设置它。但是当我执行脚本时,程序似乎停在那里。我尝试从 Lua 脚本返回 true,但没有得到任何响应。
private void calculateSetANDLogAgain(User user)
long startTime = ((long) redisTemplate.opsForHash().get("times", user.getId()));
logger.info("Received message -> " + user.toString());
long duration = 0L;
duration = System.currentTimeMillis() - startTime;
Object[] args = new Object[1];
args[0] = duration;
System.out.println("BEFORE");
boolean a = redisTemplate.execute(statisticScript, Collections.singletonList("a"),args);
System.out.println("AFTER: " + a);
在这里我看到之前但我看不到打印后。这是关于脚本执行的log 输出和配置。这是我的class tree。请注意,RedisConfig
类具有以下 bean。
@Bean
public DefaultRedisScript<Boolean> redisscript()
DefaultRedisScript defaultRedisScript = new DefaultRedisScript<>();
defaultRedisScript.setLocation(new ClassPathResource("statistics.lua"));
defaultRedisScript.setResultType(Boolean.class);
return defaultRedisScript;
我在拥有calculateSetANDLogAgain
方法的类中自动装配DefaultRedisScript
实例。脚本文件只有“return true;
”
编辑;如果有帮助,这是我的第一个脚本。
local difference = tonumber(ARGV[1])
local max = tonumber(redis.call("GET","max"))
local min = tonumber(redis.call("GET","min"))
if max == nil then
redis.call("SET","max",difference)
elseif difference > max then
redis.call("SET","max",difference)
end
if min == nil then
redis.call("SET","min",difference)
elseif difference < min then
redis.call("SET","min",difference)
end
那么可能出了什么问题?我想不通...
【问题讨论】:
【参考方案1】:我解决了这个问题。这很奇怪,但似乎失败的根源是错误的类路径。我对代码进行了一些更改,请看一下。
这是Bean
的定义。
@Bean
public DefaultRedisScript<Boolean> redisscript()
DefaultRedisScript defaultRedisScript = new DefaultRedisScript<Boolean>();
defaultRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("statistics.lua")));
defaultRedisScript.setResultType(Boolean.class);
return defaultRedisScript;
这是calculateSetANDLogAgain
函数。
private void calculateSetANDLogAgain(User user)
long startTime = ((long) redisTemplate.opsForHash().get("times", user.getId()));
logger.info("Received message -> " + user.toString());
Long duration = null;
duration = System.currentTimeMillis() - startTime;
Object[] args = new Object[1];
args[0] = duration;
try
redisTemplate.execute(statisticScript, null, args);
catch (Exception e)
finalLogger.info("Error while executing script -> " + e.getLocalizedMessage());
这是脚本;
local difference = tonumber(ARGV[1])
local max = tonumber(redis.call("GET","max"))
local min = tonumber(redis.call("GET","min"))
if max == nil then
redis.call("SET","max",tostring(difference));
elseif difference > max then
redis.call("SET","max",tostring(difference));
end
if min == nil then
redis.call("SET","min",tostring(difference));
elseif difference < min then
redis.call("SET","min",tostring(difference));
end
return nil;
最后我的脚本在资源文件夹中,我在构造函数中注入了 redistemplate。
【讨论】:
以上是关于使用 RedisTemplate 执行 Lua 脚本永远不起作用的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot通过RedisTemplate执行Lua脚本
springboot redis 用RedisTemplate执行lua脚本报错:@user_script:1: ERR value is not an integer or out of range