JedisDataException: Please close pipeline or multi block before calling this method

错误原因

transaction错误使用

pipeline错误使用

具体分析

transaction错误使用

    • Redis事务的执行结果是在exec之后才统一返回,所以Jedis会用一个Response对象最为事务对象transaction的执行放回值。如果我们在transaction执行exec方法之前调用response对象的get方法会出现异常:
    • Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: Please close pipeline or multi block before calling this method.
    • 更多Redis事务操作,请移步:Redis事务:用法,常见错误和API_琦彦-CSDN博客

    pipeline错误使用

    1.异常堆栈

    redis.clients.jedis.exceptions.JedisDataException: Please close pipeline or multi block before calling this method.

    2.异常描述:

    在pipeline.sync()执行之前,通过response.get()获取值,在pipeline.sync()执行前,命令没有执行(可以通过monitor做验证),下面代码就会引起上述异常

    Jedis jedis = new Jedis("127.0.0.1", 6379);
    Pipeline pipeline = jedis.pipelined();
    pipeline.set("hello", "world"); 
    pipeline.set("java", "jedis");
        
    Response<String> pipeString = pipeline.get("java");
    //这个get必须在sync之后,如果是批量获取值建议直接用List<Object> objectList = pipeline.syncAndReturnAll();
    System.out.println(pipeString.get());
    //命令此时真正执行
    pipeline.sync();

    Jedis中Reponse中get()方法,有个判断:如果set=false就会报错,而response中的set初始化为false.

    public T get() {
      // if response has dependency response and dependency is not built,
      // build it first and no more!!
      if (dependency != null && dependency.set && !dependency.built) {
        dependency.build();
      }
      if (!set) {
        throw new JedisDataException(
            "Please close pipeline or multi block before calling this method.");
      }
      if (!built) {
        build();
      }
      if (exception != null) {
        throw exception;
      }
      return response;
    }

    pipeline.sync()会每个结果设置set=true。

    public void sync() {
      if (getPipelinedResponseLength() > 0) {
        List<Object> unformatted = client.getAll();
        for (Object o : unformatted) {
          generateResponse(o);
        }
      }
    }

    其中generateResponse(o):

    protected Response<?> generateResponse(Object data) {
      Response<?> response = pipelinedResponses.poll();
      if (response != null) {
        response.set(data);
      }
      return response;
    }

    其中response.set(data);

    public void set(Object data) {
        this.data = data;
        set = true;
    }

    3.解决方法:

    实际上对于批量结果的解析,建议使用pipeline.syncAndReturnAll()来实现,下面操作模拟了批量hgetAll

    /**
    * pipeline模拟批量hgetAll
    * @param keyList
    * @return
    */
    public Map<String, Map<String, String>> mHgetAll(List<String> keyList) {
    // 1.生成pipeline对象
    Pipeline pipeline = jedis.pipelined();
    // 2.pipeline执行命令,注意此时命令并未真正执行
    for (String key : keyList) {
      pipeline.hgetAll(key);
    }
    // 3.执行命令 syncAndReturnAll()返回结果
    List<Object> objectList = pipeline.syncAndReturnAll();
    if (objectList == null || objectList.isEmpty()) {
      return Collections.emptyMap();
    }
        
    // 4.解析结果
    Map<String,Map<String, String>> resultMap = new HashMap<String, Map<String,String>>();
    for (int i = 0; i < objectList.size(); i++) {
      Object object = objectList.get(i);
      Map<String, String> map = (Map<String, String>) object;
      String key = keyList.get(i);
      resultMap.put(key, map);
    }
    return resultMap;
    }

    4.处理人:

    修改业务代码。

    参考来源:https://yq.aliyun.com/articles/236384?spm=a2c4e.11155435.0.0.e21e2612uQAVoW#cc1

    上一篇:Redis:EVAL执行Lua脚本


    下一篇:Linux新增磁盘和手动分区解析以及磁盘挂载解析