RedisTemplate写入Redis数据出现无意义乱码前缀\xac\xed\x00\x05

本文揭秘Spring RedisTemplate中出现的无意义乱码前缀,解析其由ObjectOutputStream序列化机制产生的原因,并指导如何利用这些知识在实际排查缓存问题时使用。建议使用StringRedisSerializer替换默认配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

项目使用Spring的RedisTemplate进行Redis数据存取操作,实际应用中发现Redis中key和value会出现“无意义”乱码前缀\xac\xed\x00\x05t\x00-(样例\xac\xed\x00\x05t\x00-abcd:abc:xxxxxx:passport:associated:key:29708)。

这个乱码前缀是怎么产生的呢?有什么含义?是不是固定的?带着这三个问题,我们一探究竟。

疑问探究

怎么产生的

org.springframework.data.redis.core.RedisTemplate实例化需要序列化和反序列化组件,如果我们不指定,默认使用org.springframework.data.redis.serializer.JdkSerializationRedisSerializer进行序列化,而JdkSerializationRedisSerializer最终使用的是Java原生java.io.ObjectOutputStream.ObjectOutputStream(OutputStream)进行序列化。

这个乱码前缀就是ObjectOutputStream进行序列化时添加的。

有什么含义

\x对应0x

\xac\xed对应是0xaced,是ObjectOutputStream的序列化魔数(见java.io.ObjectStreamConstants.STREAM_MAGIC)。

\x00\x05对应是5,是ObjectOutputStream的序列化版本(见java.io.ObjectStreamConstants.STREAM_VERSION)。

这里引出一个小问题:为什么是\x00\x05而不是\x05?

因为上面2个值write时采用的是short,占2个字节。

样例乱码\x05后面有个t,不是很明显。t是转化后的ASCII码值对应字符,对应16进制是0x74,是ObjectOutputStream分配给String类型标记(见java.io.ObjectStreamConstants.TC_STRING)。

\x00-是有\x00和-组成的,是一起的,表示数据的字节数。-是转化后的ASCII码值对应字符,对应16进制是0x2d(10进制是45,样例abcd:abc:xxxxxx:passport:associated:key:29708的字符数就是45,1个字符1个字节,字节数也是45)。

是不是固定的

由上面的描述可知,乱码前缀中\xac\xed\x00\x05是固定的,t在String类型情况是不变的,后面2个位(样例\x00-)是数据的字节数,是随key动态变化的。

衍生疑问

为什么显示不一样

为什么有些16进制\x显示,有些ASCII码值对应字符显示?

结合ASCII码对应的字符表,推测和显示系统能支持的字符集有关。

0x20 到 0x7e,都是比较正常的字符,可以显示出来。

参考ASCII码
在这里插入图片描述
在这里插入图片描述

字符长度超长会怎样

2个字节表示数据字节数,即最大0xffff,10进制为65535,key长度超过后会怎么样?

经试验,

key长度65535时,乱码为\xac\xed\x00\x05t\xff\xff

key长度65545时,乱码为\xac\xed\x00\x05|\x00\x00\x00\x00\x00\x01\x00\x09

t上面说过,是转化后的ASCII码值对应字符,对应16进制是0x74,是ObjectOutputStream分配给String类型标记(见java.io.ObjectStreamConstants.TC_STRING)。

|也是转化后的ASCII码值对应字符,对应16进制是0x7c,是ObjectOutputStream分配给长字符串类型标记(见java.io.ObjectStreamConstants.TC_LONGSTRING)。

同时,表示数据字节数的数值位数也变成了8位bigint。

综上,不用担心key长度越界。

应用

通过上面的探究,我们知道了“无意义”乱码前缀的含义。

如果我们新接手一个系统,它是这样使用RedisTemplate的。现在我们需要排查一个和缓存相关的问题,需要看下Redis中某个缓存值是否存在?

我们梳理业务组合出key,通过redis-cli尝试get key是获取不到结果的,此时我们可以根据上面规则自己生成“乱码前缀”,通过get “乱码前缀”+key 就可以判断缓存值是否存在了。

总结

  1. 上面使用RedisTemplate的方式是不好的,实际应用中key序列化可以采用StringRedisSerializer。这也是网上大部分文章建议的。
  2. 大部分文章只说了表象原因,没有分析更深入的原因。对从已存在数据中排查问题没有帮助,还是需要自己深究。
### 可能的原因分析 在使用 Redis Desktop Manager (RDM) 查看 Redis 数据时,如果出现乱码现象,通常可能由以下几个原因引起: 1. **编码不匹配**:Redis储的数据可能是二进制或者特定编码格式(如 UTF-8),而 RDM 默认解析方式未能正确识别这些数据的编码[^1]。 2. **键值类型错误解读**:某些复杂类型的键值(如哈希表、列表等)可能会因为展示逻辑的不同而导致显示异常[^2]。 3. **客户端配置问题**:RDM 的设置选项未调整到适合当前 Redis 实例的工作模式。 --- ### 解决方案 #### 方法一:确认并修改字符集编码 确保 Redis 储的数据是以可读的形式保。如果是通过程序写入数据,则需检查其编码是否为标准 UTF-8 或 ASCII 编码。如果不是,可以尝试手动转换编码后再Redis。例如,在 Python 脚本中可以通过如下方法实现字符串转码: ```python value = "你好".encode('utf-8') # 将中文字符串转化为字节流形式再储至 Redis redis_client.set("key", value) ``` 对于已经在的乱码数据,可以在取出后重新解码处理: ```python data = redis_client.get("key").decode('utf-8', errors='ignore') print(data) ``` 此操作能够忽略无法正常解码的部分,从而减少视觉上的混乱感[^3]。 #### 方法二:更新或更换工具版本 有时旧版软件可能在兼容性缺陷,建议升级到最新稳定发布的 Redis Desktop Manager 版本来获得更好的支持体验。另外也可以考虑试用其他开源替代品比如 [Medis](https://github.com/luin/medis),它提供了更灵活丰富的可视化功能以及更高的稳定性表现[^4]。 #### 方法三:自定义序列化机制 当业务场景允许的情况下,采用 JSON 序列化的手段封装对象结构会更加直观易懂。这样即使遇到复杂的嵌套关系也容易被大多数 GUI 工具所理解呈现出来。下面是一个简单的例子演示如何利用 json.dumps() 函数完成这一目标: ```python import json complex_data = {"name": "Alice", "age": 25, "city": "New York"} serialized_data = json.dumps(complex_data) # Store serialized data into Redis redis_client.set("user_profile", serialized_data) ``` 之后从数据库提取该记录的时候只需简单调用 `json.loads()` 即可还原原始状态[^5]。 --- ### 注意事项 尽管以上措施能在很大程度上缓解因技术差异带来的困扰,但在实际应用过程中仍需要注意以下几点: - 如果项目涉及国际化需求,请始终优先选用 Unicode 家族中的通用子集作为内部交换媒介; - 频繁变更基础架构之前务必做好充分测试验证工作以免引入新的隐患风险; - 对于敏感信息加密传输过程同样不可忽视安全防护策略部署实施情况评估审查流程管理等方面的要求约束条件限制因素考量要点等内容[^6]。 ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值