日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Redis使用教程之jedis客戶端sendCommand方法的byte[]入參,防止混淆string的byte與數值byte的區別

作者:Mint6 更新時間: 2023-07-22 編程語言

1.背景

在使用jedis客戶端操作redis數據的過程中,發現了一個通用的方法sendCommand,封裝了redis的所有命令,代碼路徑:redis.clients.jedis.BinaryJedis#sendCommand(redis.clients.jedis.commands.ProtocolCommand, byte[]...),具體代碼如下

    public Object sendCommand(ProtocolCommand cmd, byte[]... args) {
        this.checkIsInMultiOrPipeline();
        this.client.sendCommand(cmd, args);
        return this.client.getOne();
    }

2.封裝使用sendCommand方法

封裝代碼

public void sendCommandWrapper(List<List<byte[]>> commandList) {
            Jedis jedis = new Jedis("127.0.0.1",3306);
            for (List<byte[]> command : commandList) {
                byte[][] splitResult = command.stream().toArray(byte[][]::new);
                for (byte[] cmd : command) {
                   jedis.sendCommand(() -> splitResult[0],
                        Arrays.copyOfRange(splitResult, 1, splitResult.length));
            }
    }
}

方法入參

參數類似如下

[[["set"],["a"],["v"]],[["set"],["a"],["b"]]],[["set"],["a"],["1"]]]]

然后把每個字符換成byte

[[[115, 101, 116], [97], [118]], [[115, 101, 116], [97], [98]], [[115, 101, 116], [97], [49]]]

3.存在的問題

sendCommand方法可以傳遞string的命令轉成的byte[]參數,但是其中有兩個特例

需要注意的特例

zset的score是有符號的浮點型

Pexpireat key 時間戳:時間戳是long型

問題歸納

以“Pexpireat key 時間戳”命令為例,long型時間戳通過redis協議到redis底層存儲是byte[]的方式,使用sendCommand的時候傳遞的命令入參也是byte[],但是這兩種byte[]不是同一種byte[]。

這兩種 byte[] 不同的主要原因是它們所表示的含義不同。

在使用 Redis 命令時,我們需要將命令的參數轉換為 byte[] 格式,以便可以發送給 Redis 服務器。這里的 byte[] 實際上是字符串的字節數組表示。Redis 協議是基于文本的,即它要求在與服務器通信時發送文本字符串,因此發送給 Redis 服務器的 byte[] 實際上是表示字符串的字節數組。

String.valueOf(redisTTLLong).getBytes(StandardCharsets.UTF_8)

而在 Redis 底層存儲中,時間戳所表示的含義是一個數字,而不是一個字符串。在底層存儲中,Redis 將時間戳轉換為了二進制形式,即一個 byte[] 數組。這個 byte[] 數組表示的是一個數字,它在內存中以二進制補碼的形式存儲。

//比如從底層取出來的byte,想轉回時間戳需要的轉換邏輯:?byte轉long 
private static long convertRedisTTLToTimestamp(byte[] ttlBytes) {
        // Convert the byte array to an 8-byte binary string
        byte[] binaryBytes = new byte[8];
        for (int i = 0; i < 8; i++) {
            binaryBytes[i] = i < ttlBytes.length ? ttlBytes[i] : 0;
            if (binaryBytes[i] < 0) {
                binaryBytes[i] += 256;
            }
        }
        // Rearrange the binary string according to the big endian byte order
        long timestamp = 0L;
        for (int i = 0; i < 8; i++) {
            timestamp = (timestamp << 8) + (binaryBytes[i] & 0xff);
        }
        // returns the converted timestamp in milliseconds
        return timestamp;
    }

因此,這兩種 byte[] 不同的原因在于它們所表示的含義不同。一個表示字符串,一個表示數字的二進制補碼。雖然它們都是 byte[] 類型,但它們的內部存儲和解析方式是不同的

4.總結

使用jedis的sendCommand命令時,要記住要傳入的參數,原本屬于數值類型時,需要轉byte[]數組是直接轉成字符串的字節數組。也就是把long時間戳通過String.valueOf(redisTTLLong).getBytes(StandardCharsets.UTF_8)命令轉換出來的byte[]。

請勿與long轉byte等相關的補碼、大小端等概念混淆。

原文鏈接:https://blog.csdn.net/Mint6/article/details/130036916

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新