跳转到内容

Redis 序列化方案


Redis 只能存储字节数组,Java 对象在存入 Redis 前必须序列化为字节,取出时再反序列化为对象。序列化方案的选择直接影响:

维度影响
可读性Redis 管理台中能否直观查看数据
体积影响内存占用和网络传输效率
性能序列化/反序列化的 CPU 开销
兼容性跨语言消费、类名变更后能否正常反序列化
方案实现类可读性体积性能跨语言推荐度
JDK 序列化JdkSerializationRedisSerializer❌ 乱码最大❌ 不推荐
String 序列化StringRedisSerializer最小最高✅ 纯字符串场景
JSON 序列化Jackson2JsonRedisSerializer✅ 推荐
GenericJackson2GenericJackson2JsonRedisSerializer中(含类名)⚠️✅ 多类型场景

RedisTemplate 未配置时默认使用 JDK 序列化,将对象转为 Java 二进制字节流。

// 使用默认 RedisTemplate(JDK 序列化)
redisTemplate.opsForValue().set("user:1", new User("Alice", 25));
// Redis 中实际存储:
// Key: \xac\xed\x00\x05t\x00\x06user:1 ← key 也被序列化,带乱码前缀
// Value: \xac\xed\x00\x05sr\x00\x04User... ← value 是二进制,不可读

问题:

  • key 包含乱码前缀,KEYS user:* 无法正确匹配
  • value 不可读,无法在管理台调试
  • 强依赖 Java,跨语言消费无法反序列化
  • 类名/包名变更后反序列化失败

只能存储字符串,适合 StringRedisTemplate 或作为 key 的序列化器。

// 存对象:手动 JSON 转换
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("Alice", 25);
stringRedisTemplate.opsForValue().set("user:1", objectMapper.writeValueAsString(user));
// 取对象:手动反序列化
String json = stringRedisTemplate.opsForValue().get("user:1");
User result = objectMapper.readValue(json, User.class);

Redis 中存储:

Key: user:1 ← 干净可读
Value: {"name":"Alice","age":25} ← 标准 JSON

5. Jackson2JsonRedisSerializer(推荐)

Section titled “5. Jackson2JsonRedisSerializer(推荐)”

使用 Jackson 将对象序列化为 JSON,需要指定具体类型。

@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// Key / HashKey 使用 String 序列化(保证 key 可读)
StringRedisSerializer stringSerializer = new StringRedisSerializer();
template.setKeySerializer(stringSerializer);
template.setHashKeySerializer(stringSerializer);
// Value / HashValue 使用 Jackson JSON 序列化
Jackson2JsonRedisSerializer<Object> jsonSerializer =
new Jackson2JsonRedisSerializer<>(Object.class);
template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);
template.afterPropertiesSet();
return template;
}
}
// 存对象(自动序列化为 JSON)
redisTemplate.opsForValue().set("user:1", new User("Alice", 25));
// ❌ 错误:直接强转失败,Jackson 反序列化 Object 类型返回 LinkedHashMap
User wrong = (User) redisTemplate.opsForValue().get("user:1");
// ✅ 正确:用 ObjectMapper 二次转换
Object raw = redisTemplate.opsForValue().get("user:1");
User correct = new ObjectMapper().convertValue(raw, User.class);

在 JSON 中自动写入 @class 类型信息,反序列化时自动还原为正确的 Java 类型。

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
// 自动写入并读取类型信息
GenericJackson2JsonRedisSerializer jsonSerializer =
new GenericJackson2JsonRedisSerializer();
template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);
template.afterPropertiesSet();
return template;
}

Redis 中存储(含类型信息):

{
"@class": "com.example.dto.User",
"name": "Alice",
"age": 25
}
// 存/取无需手动指定类型
redisTemplate.opsForValue().set("user:1", new User("Alice", 25));
User user = (User) redisTemplate.opsForValue().get("user:1"); // 自动还原类型

7. 推荐方案:StringRedisTemplate + 手动 JSON

Section titled “7. 推荐方案:StringRedisTemplate + 手动 JSON”

生产环境最推荐:序列化过程完全透明,类型安全,无任何隐患。

@Component
@RequiredArgsConstructor
public class RedisUtil {
private final StringRedisTemplate redisTemplate;
private final ObjectMapper objectMapper;
public void set(String key, Object value, long ttl, TimeUnit unit) {
try {
redisTemplate.opsForValue().set(key,
objectMapper.writeValueAsString(value), ttl, unit);
} catch (JsonProcessingException e) {
throw new RuntimeException("Redis 序列化失败", e);
}
}
// 单一类型反序列化
public <T> T get(String key, Class<T> type) {
String json = redisTemplate.opsForValue().get(key);
if (json == null) return null;
try {
return objectMapper.readValue(json, type);
} catch (JsonProcessingException e) {
throw new RuntimeException("Redis 反序列化失败", e);
}
}
// 泛型反序列化(如 List<User>)
public <T> T get(String key, TypeReference<T> typeRef) {
String json = redisTemplate.opsForValue().get(key);
if (json == null) return null;
try {
return objectMapper.readValue(json, typeRef);
} catch (JsonProcessingException e) {
throw new RuntimeException("Redis 反序列化失败", e);
}
}
public void delete(String key) { redisTemplate.delete(key); }
public Boolean hasKey(String key) { return redisTemplate.hasKey(key); }
public void expire(String key, long ttl, TimeUnit unit) {
redisTemplate.expire(key, ttl, unit);
}
}
// 单一类型
User user = redisUtil.get("user:1001", User.class);
// 泛型列表
List<User> users = redisUtil.get("user:list", new TypeReference<List<User>>() {});
// 存对象
redisUtil.set("user:1001", user, 1, TimeUnit.HOURS);
存储类型?
├── 纯字符串(Token、验证码)
│ └──▶ StringRedisTemplate 直接 set/get
├── Java 对象(项目内使用)
│ └──▶ StringRedisTemplate + 手动 JSON(推荐)✅
├── 多种类型混存(需自动还原类型)
│ └──▶ GenericJackson2JsonRedisSerializer(接受 @class 开销)
└── 跨语言消费(Python / Go 等)
└──▶ StringRedisTemplate + 手动 JSON(标准 JSON,无 @class 污染)✅