使用 Lua 脚本批量获取制定目录下的所有 Redis 键的值

北风几吹夏 / 2024-10-15 / 原文

/**
 * 使用 Lua 脚本批量获取 Redis 键的值
 *
 * @param prefix Redis 中的键列表
 * @return 键对应的值的列表
 */
public <E> List<E> getAllListValuesByPrefix(String prefix, Class<?> classType) {
    // 获取所有以给定前缀开头的键
    Set<String> keys = redisTemplate.keys(prefix + ":*"); // 使用通配符查找匹配的键
    // 参数校验
    if (keys == null || keys.isEmpty()) {
        return Collections.emptyList();
    }
    String cmd;
    if (classType.isAssignableFrom(String.class)) {
        cmd = "redis.call('GET', key)";
    } else if (classType.isAssignableFrom(List.class)) {
        cmd = "redis.call('LRANGE', key, 0, -1)";
    } else if (classType.isAssignableFrom(HashMap.class)) {
        cmd = "redis.call('HVALS', key)";
        // cmd = "redis.call('HGETALL', key)";
    } else {
        throw new RuntimeException("不支持的classType类型");
    }
    // Lua脚本:批量获取所有传入keys的值
    String luaScript = "local result = {} " +
            "for i, key in ipairs(KEYS) do " +
            "    local value = " + cmd +
            "    result[i] = value " +
            "end " +
            "return result";

    // 构建 RedisScript 对象,指定返回类型为 List
    DefaultRedisScript<List> redisScript = new DefaultRedisScript<>();
    redisScript.setScriptText(luaScript);
    redisScript.setResultType(List.class);
    // 执行 Lua 脚本并返回结果
    try {
        Object result = redisTemplate.execute(redisScript, Arrays.asList(keys.toArray()));
        if (result instanceof List) {
            return (List<E>) result;
        } else {
            return Collections.emptyList();
        }
    } catch (Exception e) {
        e.printStackTrace();
        return Collections.emptyList();
    }
}