(已解决)RedisTemplate写入数据 \xAC\xED\x00\x05t\x00 序列化问题

本文介绍了在Spring中使用RedisTemplate进行数据缓存时遇到的序列化问题,展示了key和value出现的序列化异常。通过提供一个配置类设置自定义的StringRedisSerializer和Jackson2JsonRedisSerializer来解决这个问题,确保key和value都能正确序列化为String和Json格式。同时给出了具体的代码示例,展示了如何在实际应用中设置和使用RedisTemplate进行缓存操作。

先看现象:

 

 Spring使用RedisTemplate进行数据缓存的时候,发现缓存的数据有序列化问题

话不多说,上图

 不仅仅是key出现这种序列化问题,而且value也会出现这种情况

先把解决方案放着,要不有的人嫌事多

@Configuration
public class RedisTemplateSerializer {

    public RedisTemplate redisTemplate;

    @Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisSerializer stringSerializer = new StringRedisSerializer();//序列化为String
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//序列化为Json
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        this.redisTemplate = redisTemplate;
    }
}

然后在使用redisTemplate写入缓存的地方

@Resource
RedisTemplate redisTemplate;

public void xx(String key, Object value) {
    //缓存写入
    redisTemplate.opsForValue().set(key, object, 1, TimeUnit.HOURS);
    //缓存获取
    redisTemplate.opsForValue().get(key);
    ...
}

实际的逻辑代码自己来写。

<think>我们查询的字符串是:`\xac\xed\x00\x05sr\x00` 根据引用[1][2][3]的信息,这种前缀通常是由于使用了默认的JDK序列化(`JdkSerializationRedisSerializer`)导致的。具体来说: - `\xac\xed`:这两个字节是Java序列化流的魔数(Magic Number),固定为0xACED(即Java序列化协议标识)。 - `\x00\x05`:接下来的两个字节是版本号,这里值为5。 - 紧接着的`sr`(对应十六进制0x73 0x72)是`ObjectStreamConstants.STC_OBJECT`的标识,表示一个对象。 因此,`\xac\xed\x00\x05sr\x00`这一串字节序列是Java对象序列化后的头部特征。 具体解释: - `\xac\xed`:魔数(固定) - `\x00\x05`:流版本(这里为5,对应JDK版本) - `sr`:表示这是一个新对象(TC_OBJECT)和一个新类描述符(TC_CLASSDESC)的开始。 - 后面的`\x00`是类名的长度(这里暂时没有出现,因为类名还在后面)的一部分。 所以,这个序列化类型是**Java原生序列化(JDK Serialization)**。 解决这种乱码前缀的方法(如引用[4][5]所示)是配置RedisTemplate,使用其他序列化器,例如: 1. `StringRedisSerializer`:用于字符串键和值。 2. `GenericJackson2JsonRedisSerializer`:使用JSON格式,可读性好。 3. `GenericFastJsonRedisSerializer`:FastJson提供的序列化器。 配置示例(参考引用[5]): ```java @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); // 使用StringRedisSerializer来序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); // 设置hash key和value的序列化模式 template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } } ``` 这样配置后,存储在Redis中的键和值就不会有Java序列化的前缀了。 相关问题: 1. 如何识别不同序列化器生成的Redis键值特征? 2. 除了JSON序列化,还有哪些常用的Redis序列化方案?各有何优缺点? 3. 在使用Spring Data Redis时,如何为不同的数据类型配置不同的序列化器? 4. 为什么Java原生序列化会产生较长的前缀?其设计原理是什么? </think>### 序列化类型识别结果 字符串 `\xac\xed\x00\x05sr\x00` 是 **Java 原生序列化(JDK Serialization)** 的特征前缀,具体分析如下: #### 字节序列解析 | 十六进制 | 含义 | 说明 | |----------|-------------------------------|------------------------------------------| | `\xac\xed` | 魔数 (Magic Number) | Java 序列化流的固定标识符 `0xACED`[^1] | | `\x00\x05` | 版本号 (Stream Version) | 表示序列化协议版本(此例为 JDK 5)[^2] | | `sr` | 对象类型标记 (TC_OBJECT) | `0x73 0x72` 表示新对象的开始[^3] | | `\x00` | 类名长度占位符 | 后续将声明类名的 UTF 字节长度 | #### 特征对照表 | 序列化类型 | 特征前缀 | 可视化表现 | |-------------------------------|---------------------------|--------------------------| | JDK 序列化 | `\xac\xed\x00\x05t\x00` | 键值出现乱码(如 `\xac\xed\x00\x05t\x00*`)[^2][^3] | | StringRedisSerializer | 无前缀 | 原始字符串(如 `user:1`) | | Jackson/JSON 序列化 | `{` 或 `["` | JSON 结构(如 `{"name":"Alice"}`) | ### 解决方案(消除乱码) 在 `RedisTemplate` 中配置序列化器,覆盖默认的 JDK 序列化: ```java @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); // 使用字符串序列化器(消除乱码) template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new StringRedisSerializer()); // 如需存储对象,改用 JSON 序列化器 // template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } } ``` > **关键点**: > - `StringRedisSerializer` 直接存储 UTF-8 字符串,彻底消除前缀[^5] > - `GenericJackson2JsonRedisSerializer` 存储 JSON 时会添加 `@class` 类型标记(如 `["java.util.ArrayList",[...]]`)[^4] ### 验证效果 执行前(JDK 序列化): ```bash > KEYS * 1) "\xac\xed\x00\x05t\x00\x0duser_session:1" ``` 执行后(正确序列化): ```bash > KEYS * 1) "user_session:1" ``` ### 相关问题 1. **JDK 序列化为何会产生 `\xac\xed` 前缀**? 这是 Java 对象序列化流的固定魔数,用于标识序列化格式[^1][^3]。 2. **`GenericJackson2JsonRedisSerializer` 如何处理嵌套泛型**? 通过 `@class` 字段存储原始类型信息(如 `com.example.User`),但可能引入安全风险[^4]。 3. **如何在 Redis 中识别其他序列化格式**? - **MessagePack**: 前缀 `82 A1` (二进制格式) - **Protobuf**: 前缀 `0A` (字段标签+类型) 4. **为何不推荐在生产环境使用 JDK 序列化**? 存在安全漏洞(反序列化攻击)、存储效率低、跨语言兼容性差[^1][^5]。 [^1]: 未配置序列化时使用 JDK 默认实现导致乱码 [^2]: JDK 序列化在 Redis 键值中产生特定前缀 [^3]: \xac\xedJava 序列化流的魔数标识 [^4]: 推荐使用 JSON 序列化器替代原生序列化 [^5]: 通过 StringRedisSerializer 可直接消除乱码
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值