zoukankan      html  css  js  c++  java
  • jedis的scan操作要注意cursor数据类型

    环境

    jedis3.0.0

    背景

    在使用jedis的"scan"操作获取redis中某些key时,发现总是出现类型转换的异常——"java.lang.ClassCastException: java.lang.String cannot be cast to [B"

    其中,redis中存储的key是byte[]类型,用"scan"操作获取的所有key是封装到一个List<T>中,获取结果后直接通过Set.addAll()存到一个HashSet<byte[]>中,就在用forEach遍历该HashSet时抛出了异常。

    Debug

    Why

    经过debug发现这跟调用"scan(cursor,params)"时传的"cursor"的类型有关。


    如上两图所示:

    • 当cursor为String类型时,调用的是Jedis类中的scan方法;
    • 当cursor为byte[]类型时,调用的则是BinaryJedis中的scan方法。

    Jedis类是BinaryJedis的子类

    What

    接下来看下两者的scan方法——
    Jedis.scan(final String cursor, final ScanParams params):

    @Override
      public ScanResult<String> scan(final String cursor, final ScanParams params) {
        checkIsInMultiOrPipeline();
        client.scan(cursor, params);
        List<Object> result = client.getObjectMultiBulkReply();
        String newcursor = new String((byte[]) result.get(0));
        List<String> results = new ArrayList<String>();
        List<byte[]> rawResults = (List<byte[]>) result.get(1);
        for (byte[] bs : rawResults) {
          results.add(SafeEncoder.encode(bs));
        }
        return new ScanResult<String>(newcursor, results);
      }
    

    BinaryJedis.scan(final byte[] cursor, final ScanParams params):

    public ScanResult<byte[]> scan(final byte[] cursor, final ScanParams params) {
        checkIsInMultiOrPipeline();
        client.scan(cursor, params);
        List<Object> result = client.getObjectMultiBulkReply();
        byte[] newcursor = (byte[]) result.get(0);
        List<byte[]> rawResults = (List<byte[]>) result.get(1);
        return new ScanResult<byte[]>(newcursor, rawResults);
    }
    

    可以发现,两者都是通过调用BinaryClient类的scan方法来获取数据,这些数据是一样的,只是两者在封装返回结果时的操作不同而已。BinaryJedis把byte[]类型的原始数据原封不动地返回,而Jedis则是用SafeEncode把原始数据encode成String类型返回。

    How

    一开始没意识到scan("0",params)scan("0".getBytes(),params)返回结果不同,直接用了前者,结果前者返回的是List<String>类型的数据,直接用addAll(ScanResult.getResult())方法放到HashSet<byte[]>中,而编译器这时是没有提示的,所以自然而然,在遍历HashSet时就抛出了异常。


    注:ScanResult提供两个方法获取游标,分别是getCursor()getCursorAsBytes(),前者是String类型,后者是byte[]类型,使用时需要注意。

    拓展

    此时又产生了新的疑惑,会不会在ScanParams中也存在类似的问题?于是进ScanParams类查看

    发现这里对match方法进行了重载(Overload),传入byte[]和String类型的参数结果是一样的。所以ScanParams的pattern可以用String或者byte[]。

    启发

    在开发中,一定一定一定要注意变量类型,尤其是集合中的泛型。有必要的话,在类型转换前或者在集合类的操作中对变量进行类型检查。

  • 相关阅读:
    T-SQL---多值模糊查询的处理
    SQL Server 并行操作优化,避免并行操作被抑制而影响SQL的执行效率
    SQL Server创建复合索引时,复合索引列顺序对查询的性能影响
    Sql Server 聚集索引扫描 Scan Direction的两种方式------FORWARD 和 BACKWARD
    Sql Server 内存相关计数器以及内存压力诊断
    通过手动创建统计信息优化sql查询性能案例
    对聚集表查询的时候,未显式指定排序列的时候,默认查询结果的顺序一定是按照聚集索引顺序排序的吗
    Buffer cache hit ratio性能计数器真的可以作为SQL Server 内存瓶颈的判断指标吗?
    sqlserver 存储过程中使用临时表到底会不会导致重编译
    权限 位运算
  • 原文地址:https://www.cnblogs.com/life-of-coding/p/12023036.html
Copyright © 2011-2022 走看看