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

啟發

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM