RedisTemplate默认使用JdkSerializationRedisSerializer导致乱码,因其添加\xac\xed\x00\x05等魔数二进制头;应显式配置StringRedisSerializer或Jackson2JsonRedisSerializer,并覆盖key、value、hash等全部序列化器。

RedisTemplate默认用JdkSerializationRedisSerializer是历史惯性,不是设计优选
Spring Data Redis 从早期就绑定 JDK 原生序列化作为兜底方案,原因很实际:它不依赖第三方库、能自动处理任意 Serializable 类型、无需声明泛型或配置类型信息。但代价是——它根本没考虑可读性、跨语言、体积和调试友好性。
这个默认值在 Spring Boot 2.x 甚至 3.x 中依然保留,不是因为合理,而是为了向后兼容。只要你没显式配置 setKeySerializer 或 setValueSerializer,RedisTemplate 就会静默启用 JdkSerializationRedisSerializer,连 warning 都不打一个。
为什么你看到的 key 和 value 全是 \xac\xed\x00\x05 开头的乱码
这是 JDK 序列化协议的固定魔数(magic number),表示“接下来是一段 Java 原生序列化数据”。Redis 本身只存字节流,它不管内容,但你用 redis-cli get your_key 看到的就是这段二进制——不是截断,也不是编码错误,就是纯二进制乱码。
-
redisTemplate.opsForValue().set("user:1", new User())存进去的 key 实际是\xac\xed\x00\x05t\x00\x08user:1,不是字符串"user:1" - value 同样被包上类名、字段描述、版本哈希等元数据,体积膨胀 30%~50%
- 任何非 JVM 客户端(Python 的 redis-py、Node.js 的 ioredis)都解析不了,连
GET出来都得靠 Java 反序列化工具才能还原
改用 Jackson 不只是“更好”,而是解决三个硬性问题
换成 Jackson2JsonRedisSerializer 不是为了炫技,而是绕不开的现实需求:
- 调试:Redis CLI / RedisInsight 里能直接看到
{"id":1,"name":"Alice"},而不是一堆十六进制 - 跨服务:Go 微服务或前端 mock 工具可以直接
GET+JSON.parse(),不用写专用反序列化逻辑 - 字段变更容忍:加个
status字段,旧数据仍能反序列化(Jackson 默认忽略未知字段);而 JDK 序列化一加字段就报InvalidClassException
注意:必须同时设 setKeySerializer(new StringRedisSerializer()),否则 key 还是乱码——很多项目只改了 value,忘了 key。
最容易被忽略的坑:HashOperations 和 ReactiveRedisTemplate 同样默认走 JDK
你以为配好 RedisTemplate 就万事大吉?错。这些地方同样默认用 JDK 序列化,且容易漏配:
-
HashOperations:即使你设了setValueSerializer,它默认仍用getDefaultSerializer()处理 hash field 和 value,必须单独调setHashKeySerializer()和setHashValueSerializer() -
ReactiveRedisTemplate:Spring Boot 自动配置的ReactiveRedisTemplate<Object, Object>同样默认 JDK 序列化,需手动替换key/value序列化器 - 缓存抽象层(
@Cacheable):如果底层用的是RedisCacheManager,它内部用的仍是RedisTemplate,没配 serializer 就等于白搭
真正的干净配置,不是“改一个地方”,而是覆盖所有序列化入口点——key、value、hash key、hash value、set member、zset score(虽然 score 是 double,但 member 是 string)、甚至过期策略里的时间戳序列化逻辑(如果自定义)。一步漏掉,就可能某天凌晨三点发现缓存删不掉、查不到、或者反序列化成 LinkedHashMap。


















