Redis 中的 key 为什么变成了乱码?——Java JDK 默认序列化问题详解与解决方案

在使用 Spring Boot 操作 Redis 的过程中,你是否遇到过这样的问题:

127.0.0.1:6379> keys *
"\xac\xed\x00\x05t\x00\r1751877165023"

你本来希望 key 是:

1751877165023

但实际却存成了一串看不懂的乱码二进制。这是怎么回事?本文将从原理、问题分析到解决方案,全面讲解这个现象的根本原因和处理方式。


一、问题背景

在 Java 项目中,我们通常使用 RedisTemplate 来操作 Redis。如果使用不当,key 和 value 可能会被以 JDK 默认序列化格式(即 JdkSerializationRedisSerializer)保存到 Redis 中,从而导致可读性差,甚至出现乱码。


二、现象复现

项目中代码如下:

@Autowired
private RedisTemplate<Object, Object> redisTemplate;

public void save() {
    redisTemplate.opsForValue().set(1751877165023L, "value");
}

然后你在 Redis 中查看 key:

127.0.0.1:6379> keys *
"\xac\xed\x00\x05t\x00\r1751877165023"

这是 Redis 中实际存储的 key,看起来完全不像你期望的字符串 1751877165023


三、原因分析:JDK 默认序列化机制

我们可以做个测试:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

@SpringBootTest
public class Test {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    RedisTemplate redisTemplate;

    @org.junit.jupiter.api.Test
    public void testSerializer(){
        String KeySerializerName = stringRedisTemplate.getKeySerializer().getClass().getName();
        System.out.println("stringRedisTemplate KeySerializerName = " + KeySerializerName);
        System.out.println("stringRedisTemplate ValueSerializerName = " + stringRedisTemplate.getValueSerializer().getClass().getName());

        String redisTemplateName = redisTemplate.getKeySerializer().getClass().getName();
        System.out.println("redisTemplate KeySerializerName = " + redisTemplateName);
        System.out.println("redisTemplate ValueSerializerName = " + redisTemplate.getValueSerializer().getClass().getName());
    }
}

上述程序输出为:

stringRedisTemplate KeySerializerName = org.springframework.data.redis.serializer.StringRedisSerializer
stringRedisTemplate ValueSerializerName = org.springframework.data.redis.serializer.StringRedisSerializer
redisTemplate KeySerializerName = org.springframework.data.redis.serializer.JdkSerializationRedisSerializer
redisTemplate ValueSerializerName = org.springframework.data.redis.serializer.JdkSerializationRedisSerializer

可以看到,在默认情况下,RedisTemplate使用的是:

JdkSerializationRedisSerializer

它会将 Java 对象(包括 key 和 value)序列化为二进制格式:

字节序列含义
\xac\xedJava 序列化魔数(固定)
\x00\x05序列化版本号
t (0x74)类型代码,代表 Java 字符串
\x00\r字符串长度(13)
1751877165023实际字符串内容

这也是为什么 Redis 中 key 被转成了这样一串二进制编码,而不是你设置的纯字符串。


四、正确做法:设置 RedisTemplate 的序列化器

我们应该手动配置 RedisTemplate 的序列化策略,最常见的做法是:

  • key / hashKey 使用 StringRedisSerializer
  • value / hashValue 使用 JSON 序列化器(如 Jackson、FastJSON2)

✅ 推荐配置示例:

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        // key 使用字符串序列化器
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());

        // value 使用 JSON 序列化器(这里用 Jackson,也可替换为 FastJSON2)
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

        template.afterPropertiesSet();
        return template;
    }
}

配置完毕后,再次写入 Redis:

redisTemplate.opsForValue().set("1751877165023", "hello");

Redis 中 key 变成了可读字符串:

127.0.0.1:6379> keys *
"1751877165023"

六、如何查看 Redis 中真实存储内容?

你可以使用以下方式查看 Redis key 的真实格式:

1. redis-cli 命令行

keys *

如果看到 \xac\xed 开头的内容,说明用了 JDK 序列化。

2. 图形化工具

如 Redis Desktop Manager、Another Redis Desktop Manager (ARDM),能更直观地看到 key 和 value 的结构。


✍️ 最后

Redis 本是一个轻量级、可视化极强的 K/V 数据库,我们在 Java 中使用它时,不应让底层的序列化方式变成阻碍调试和跨语言交互的绊脚石。合理配置序列化器,既提高了效率,也提升了代码质量。


如果你还在用默认 RedisTemplate 或发现 Redis key 是乱码,建议立刻检查序列化配置。

`RedisTemplate` 是 Spring Data Redis 提供的用于操作 Redis 的核心类,它默认使用以下**序列化方式**: --- ### 🔍 RedisTemplate 默认序列化方式 | 操作对象 | 默认使用的序列化器 | 类型 | |----------|---------------------|------| | Key(键) | `JdkSerializationRedisSerializer` | 序列化 `byte[]` | | Value(值) | `JdkSerializationRedisSerializer` | 序列化 `byte[]` | | Hash Key(哈希键) | `JdkSerializationRedisSerializer` | 序列化 `byte[]` | | Hash Value(哈希值) | `JdkSerializationRedisSerializer` | 序列化 `byte[]` | --- ### ❓ 为什么会导致 key 出现乱码? 因为 `JdkSerializationRedisSerializer` 是使用 Java 原生序列化机制(`ObjectInputStream` / `ObjectOutputStream`)将对象序列化为字节数组(`byte[]`)存储的。 当你使用 `RedisTemplate` 存储字符串 key 时,例如: ```java redisTemplate.opsForValue().set("name", "Tom"); ``` - 默认会将 `"name"` 这个字符串使用 `JdkSerializationRedisSerializer` 序列化为字节数组。 - 存入 Rediskey 并不是 `"name"`,而是一串类似 `xAC\xED\x00\x05t\x00\x04name` 的二进制数据。 - 在 Redis 客户端(如 `redis-cli`)中查看时,就显示为乱码。 --- ### ✅ 示例代码(使用默认配置) ```java @Autowired private RedisTemplate redisTemplate; public void testDefaultSerialization() { redisTemplate.opsForValue().set("username", "john_doe"); } ``` - 在 Redis 中实际存储的 key 是经过 JDK 序列化的字节数组。 - 使用 `redis-cli keys *` 查看时,key 会显示为乱码,例如:`xac\xed\x00\x05t\x00\x08username`。 --- ### ✅ 如何解决乱码问题? 你需要将 key序列化器设置为 `StringRedisSerializer`,它会将字符串直接转换为 `byte[]` 而不进行 Java 原生序列化。 --- ### ✅ 推荐配置(解决乱码) ```java @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); // 设置 key序列化方式为 StringRedisSerializer template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); // 设置 value 的序列化方式为 GenericJackson2JsonRedisSerializer(将对象转为 JSON) template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); template.afterPropertiesSet(); return template; } ``` --- ### ✅ 配置后效果 ```java redisTemplate.opsForValue().set("username", "john_doe"); ``` - 此时 Redis 中存储的 key 就是 `"username"` 字符串。 - 使用 `redis-cli` 查看时不会出现乱码。 --- ### 🧠 总结 | 内容 | 说明 | |------|------| | 默认序列化器 | `JdkSerializationRedisSerializer` | | 问题 | 导致 key 和 value 出现乱码(如 `xac\xed\x00\x05t\x00\x04name`) | | 原因 | 使用了 Java 原生序列化机制,将字符串包装成 `Serializable` 对象进行序列化 | | 解决方案 | 使用 `StringRedisSerializer` 序列化 key,使用 `GenericJackson2JsonRedisSerializer` 或 `Jackson2JsonRedisSerializer` 序列化 value | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青衫客36

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值