Spring Data Redis: Redis Pipeline 总是返回 null

我希望只使用指定字段检索多个哈希映射值。因此,我选择了 Redis pipeline。

在测试以下代码时,我发现redisResponse1始终为null,而redisResponse2具有值。

    getRedisTemplate().executePipelined(new RedisCallback<Object>() {
        @Override
        public Object doInRedis(RedisConnection connection) throws DataAccessException {
                List<byte[]> redisResponse1 = connection.hMGet(key.getBytes(), params);
                List<byte[]> redisResponse2 = getRedisTemplate().getConnectionFactory().getConnection().hMGet(key.getBytes(), specificParams);
                return null;
        }
    });

当我查看代码并发现以下内容时,

a) redisResponse2没有使用 pipeline 选项执行

b) redisResponse1使用 pipeline 执行(isPipelined()==true),但始终返回 null。

public List<byte[]> hMGet(byte[] key, byte[]... fields) {
    try {
        if (isPipelined()) {
            pipeline(new JedisResult(pipeline.hmget(key, fields)));
            return null;
        }
        if (isQueueing()) {
            transaction(new JedisResult(transaction.hmget(key, fields)));
            return null;
        }
        return jedis.hmget(key, fields);
    } catch (Exception ex) {
        throw convertJedisAccessException(ex);
    }
}

所以问题是

  1. 如何使用 pipeline 选项实现我的用例?

  2. 在此 RedisCallback 中访问 getRedisTemplate().getConnectionFactory().getConnection() 有什么影响?

  3. 整个 pipeline 概念如何工作?它像动态 Lua 一样吗?其中这段 Java 代码被转换为 Lua 脚本并作为脚本发送到 Redis,在 Redis 中执行并返回?在该回调中令人惊讶的是,该代码也访问/更新外部类变量,那么所有这些变量会发生什么?所有这些外部类变量也都发送到 lua 中吗?

  4. 我看到许多有关 doInRedis API 返回 null 的例子;为什么?如何从中返回/获取有效的对象?

点赞
用户2067527
用户2067527

大多数关于 Spring Data Redis 的问题都可以在 参考文档 中找到答案。

在深入了解 Pipelining 之前,单个来自一个 Hash 的 multi-get 不需要 Pipelining,因为它只是一个单一的命令。Pipelining 不会改善 Redis 交互的性能、稳定性等等。

Pipelining 是作为回调函数进行排列,并且旨在发出多个命令而不立即等待结果,可以将其视为一个批处理,稍后可以获得所有的结果。因为 Pipelining 在最后同步响应,所以你无法在回调函数中接收结果值,但是可以在 Pipelining 会话同步和 executePipelined(…) 终止时获得结果值。

你的代码应该像这样:

List<Object> results = getRedisTemplate().executePipelined(new RedisCallback<Object>() {

    @Override
    public Object doInRedis(RedisConnection connection) {

            connection.hMGet(key.getBytes(), params);

            return null;
    }
});

List<Object> hmget = (List<Object>) results.get(0);

因为连接已进入 Pipelining 模式,所以必须仅使用作为回调参数接收的连接。从回调外部获取连接(例如 template.getConnectionFactory().getConnection())将打开一个新连接并执行带等待响应的 Redis 命令-不会对任何外部获得的连接应用 Pipelining。

你还可以使用 RedisTemplate 的方法,而不是仅仅与简单连接一起使用。executePipelined(…) 将在当前线程中绑定在回调中使用的连接,并且如果您调用模板 API 方法,则会重用该绑定的连接。

关于你的 Lua 问题: 代码/方法调用不会转换为 Lua。

2017-09-20 14:04:06
用户9759662
用户9759662

关于问题:

  1. 我看到很多关于 doInRedis API 返回 null 的例子,为什么?如何从中返回/获取有效的对象?

以下是答案:

https://docs.spring.io/spring-data/redis/docs/current/reference/html/#pipeline

// 从队列中弹出指定数量的元素
List<Object> results = stringRedisTemplate.executePipelined(
  new RedisCallback<Object>() {
    public Object doInRedis(RedisConnection connection) throws DataAccessException {
      StringRedisConnection stringRedisConn = (StringRedisConnection)connection;
      for(int i=0; i< batchSize; i++) {
        stringRedisConn.rPop("myqueue");
      }
    return null;
  }
});

注意,从 RedisCallback 返回的值 必须为 null,因为这个值会被忽略,以返回批处理命令的结果。

2022-10-28 09:55:04