jedis的scan操做要注意cursor數據類型

環境

jedis3.0.0java

背景

在使用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時拋出了異常。redis

Debug

Why

通過debug發現這跟調用"scan(cursor,params)"時傳的"cursor"的類型有關。


如上兩圖所示:ide

  • 當cursor爲String類型時,調用的是Jedis類中的scan方法;
  • 當cursor爲byte[]類型時,調用的則是BinaryJedis中的scan方法。

Jedis類是BinaryJedis的子類
debug

What

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

@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):blog

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類型返回。ip

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[]。get

啓發

在開發中,必定必定必定要注意變量類型,尤爲是集合中的泛型。有必要的話,在類型轉換前或者在集合類的操做中對變量進行類型檢查。編譯器

相關文章
相關標籤/搜索