23 redis 中的中文字符串是以什么编码存储的?
Posted 蓝风9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了23 redis 中的中文字符串是以什么编码存储的?相关的知识,希望对你有一定的参考价值。
前言
呵呵 最近同事问到了这样的一个问题
因为在实际的场景中似乎是出现了乱码问题, 他问道 "redis 里面字符串默认是按照什么编码存放的? "
呵呵 我一愣, 字节 经过 编码 转换后就是我们常说的 字符
然后 映像中 sds 中也没有提到 编码相关阿?
呵呵 因此当时 记录下了 这个问题, 今天来看一看
这个问题 也可以扩展到 其他的 客户端 和 服务器 之间的数据交互
我们这里将着重从 服务端的编码 和 多种不同的客户端 来看一下 客户端的编码处理
"你好" 的字节序列
utf8 编码之后为 \\xe4\\xbd\\xa0\\xe5\\xa5\\xbd
gbk 编码之后为 \\xc4\\xe3\\xba\\xc3
redis-server 交互的编码
redis 中字符串对象是存储于 sds 中, 其存储核心数据的方式是 char[]
在 c/c++ 中 char 是 1 字节, 那么在服务器这边是 单字节 编码, 数据如果是出现了乱码, 那只能说明 客户端存取的编码不一致
redis-cli 交互的编码
redis-cli 这边是通过 read 函数来读取的命令行的输入, 那么这个具体的编码方式是取决于操作系统
我们可以 验证一下
在 mac 下面, 默认的 字符编码集 是 utf8
master:redis-6.2.0 jerry$ ./src/redis-cli
127.0.0.1:6379> set name 你好
OK
127.0.0.1:6379> get name
"\\xe4\\xbd\\xa0\\xe5\\xa5\\xbd"
127.0.0.1:6379>
在 linux 上面 默认的 字符编码集 是 utf8, 这里以一个 docker 容器中的 redis-cli 来进行交互
master:redis jerry$ docker exec -it redis /bin/sh
# cat /etc/issue
Debian GNU/Linux 11 \\n \\l
# redis-cli -h 192.168.0.246
192.168.0.246:6379> set name 你好
OK
192.168.0.246:6379> get name
"\\xe4\\xbd\\xa0\\xe5\\xa5\\xbd"
在 windows 上面 默认的 字符编码集 是 gbk, 这里下载了一个 windows 版本的 redis 使用其中的 redis-cli 来进行交互
PS C:\\Users\\Jerry.X.He\\Desktop\\redis-64.3.0.503> ./redis-cli -h 192.168.0.246
192.168.0.246:6379> get name
"\\xe4\\xbd\\xa0\\xe5\\xa5\\xbd"
192.168.0.246:6379> set name ᅣ ̄채
OK
192.168.0.246:6379> get name
"\\xc4\\xe3\\xba\\xc3"
直接在网上查询, 搜索也能获取到上面的信息, 但是 往往 还是更加确切一些的东西, 会更加有说服力一些, 使用 类似的代码 来读取, 然后 查看具体的内存的信息
这里不同的编码集可以使用是一个 case 来获取编码之后的结果
//
// Created by Jerry.X.He on 2021/11/6.
//
#include "stdio.h"
int main(int argc, char **argv)
char ch[10];
printf("please input ch : ");
scanf("%s", &ch);
printf("output ch : %s\\n", ch);
printf("output ch : %x %x %x %x %x %x\\n", ch[0], ch[1], ch[2], ch[3], ch[4], ch[5]);
return 0;
mac 上面演示如下
jedis 交互的编码
首先来一个简单的 case, 执行能够获取到 name 对应的 "你好"
import redis.clients.jedis.Jedis;
/**
* Test18JedisSetNihao
*
* @author Jerry.X.He <970655147@qq.com>
* @version 1.0
* @date 2021-11-06 16:53
*/
public class Test18JedisSetNihao
// Test18JedisSetNihao
public static void main(String[] args)
Jedis jedis = new Jedis("127.0.0.1", 6379);
// jedis.auth("123456");
String oldName = jedis.get("name");
// jedis.set("name", "你好");
System.out.println(oldName);
int x = 0;
跟踪一下对应的编码解码部分, 可以看到 默认使用的是一个 Protocol. CHARSET
点进去, 是一个 final 的字符串, 编码为 "utf8"
因为这个 charset 没有配置的地方, 因此如果 客户端使用 其他编码存储, 使用 jedis 读取出来会是乱码
另外因为序列本身 也不符合 utf8 的编码规范, 所以在解码的过程中 原始的字节序列都还原不了了
redisson 交互的编码
同样先来一段 case, 可以看到的是 这里是可以指定 编码方式的
/**
* Test18JedisSetNihao
*
* @author Jerry.X.He <970655147@qq.com>
* @version 1.0
* @date 2021-11-06 16:53
*/
public class Test18RedissonSetNihao
// Test18JedisSetNihao
public static void main(String[] args) throws Exception
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379").setDatabase(0);
RedissonClient redissonClient = Redisson.create(config);
StringCodec defaultCodec = StringCodec.INSTANCE;
StringCodec gbkCodec = new StringCodec(Charset.forName("gbk"));
RBucket<String> nameObjBucket = redissonClient.getBucket("name", defaultCodec);
Object nameObj = nameObjBucket.get();
int x = 0;
它的编码解码 取决于传入的 codec, 默认的 charset 为 utf8
所以 他是可以适配任意字符集的
windows 的 redis-cli 写入数据, 只要他指定 charset 为 gbk, 就可以正确的读取
linux 的 redis-cli 写入数据, 只要他指定 charset 为 utf8, 就可以正确的读取
jedis 写入的数据, 只要他指定 charset 为 utf8, 就可以正确的读取
redisson 按照 指定编码集 concreteCharset 写入的数据, 只要他指定 charset 为 concreteCharset, 就可以正确的读取
redisTemplate 交互的编码
同样来一段 case, 可以看到的是 这里是可以指定 编码方式的
/**
* Test18JedisSetNihao
*
* @author Jerry.X.He <970655147@qq.com>
* @version 1.0
* @date 2021-11-06 16:53
*/
public class Test18RedisTemplateSetNihao
// Test18JedisSetNihao
public static void main(String[] args) throws Exception
RedisStandaloneConfiguration jedisConfig = new RedisStandaloneConfiguration();
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisConfig);
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(jedisConnectionFactory);
stringRedisTemplate.setValueSerializer(new StringRedisSerializer(Charset.forName("utf8")));
// stringRedisTemplate.setValueSerializer(new StringRedisSerializer(Charset.forName("gbk")));
BoundValueOperations<String, String> nameOpts = stringRedisTemplate.boundValueOps("name");
// nameOpts.set("你好");
Object nameObj = nameOpts.get();
int x = 0;
它的编码解码 取决于配置的 valueSerializer
所以 他是可以适配任意字符集的
windows 的 redis-cli 写入数据, 只要他指定 charset 为 gbk, 就可以正确的读取
linux 的 redis-cli 写入数据, 只要他指定 charset 为 utf8, 就可以正确的读取
jedis 写入的数据, 只要他指定 charset 为 utf8, 就可以正确的读取
redisson 按照 指定编码集 concreteCharset 写入的数据, 只要他指定 charset 为 concreteCharset, 就可以正确的读取
rdisTemplate 按照 指定编码集 concreteCharset 写入的数据, 只要他指定 charset 为 concreteCharset, 就可以正确的读取
其他
这个问题 也可以扩展到 其他的 客户端 和 服务器 之间的数据交互
呵呵 这个就要你多去思考了, 更加细节的了解 为什么会产生乱码
完
以上是关于23 redis 中的中文字符串是以什么编码存储的?的主要内容,如果未能解决你的问题,请参考以下文章