当前位置: 首页 > article >正文

Redis使用教程之jedis客户端sendCommand方法的byte[]入参,防止混淆string的byte与数值byte的区别

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等相关的补码、大小端等概念混淆。


http://www.kler.cn/a/9244.html

相关文章:

  • redis实现消息队列的几种方式
  • 高性能分布式缓存Redis-高可用部署
  • 软件测试——认识测试
  • [ Linux 命令基础 3 ] Linux 命令详解-文件和目录管理命令
  • 模型压缩相关技术概念澄清(量化/剪枝/知识蒸馏)
  • srs http-flv处理过程
  • 电脑误删除的文件怎么恢复
  • 从零开始学习Blazor
  • SHELL函数可课后作业
  • 使用Schrödinger Python API系列教程 -- 介绍 (一)
  • 6.S081——虚拟内存部分——xv6源码完全解析系列(2)
  • 用于语义分割模型的t-SNE可视化
  • ftp传输文件大小有限制吗 ftp文件传输工具有哪些
  • fate-serving-server增加取数逻辑并源码编译
  • vue3中tsx语法一些了解
  • Vue+nodejs快递收发寄件揽件代取网点查询系统
  • 编译技术-优化理论
  • 【剧前爆米花--爪哇岛寻宝】java文件操作和io流
  • 应急响应真的很重要!
  • 全排列1_dfs
  • 数据安全-数据分类分级方案设计
  • Thinkphp 6.0多语言
  • SpringSession深入浅出(一)
  • Chapter2 : SpringBoot配置
  • Sharepoint Online手工迁移方案 | 分享二
  • 问题 A: C语言11.1