You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Redis中作为值存储和读取可序列化的Java对象

Redis中存储和读取可序列化Java对象的实现方案

核心问题说明

你遇到的读取报错、字节损坏异常的核心原因有两个:

  1. JDK序列化要求存储的对象必须实现Serializable接口,否则序列化、反序列化都会失败
  2. 直接将Redis返回的结果转字符串再转字节的操作会损坏数据:序列化后的字节不属于标准UTF-8字符集,转字符串过程中会丢弃无法识别的字节,导致最终拿到的字节数组和原始序列化字节不一致

实现步骤

1 改造序列化实体类

需要存储的Java类必须显式实现Serializable接口,同时指定固定的serialVersionUID,避免类结构修改后反序列化不兼容:

import java.io.Serializable;

public class SomeObject implements Serializable {
    // 固定序列化ID,只要类的兼容字段不修改就可以正常反序列化
    private static final long serialVersionUID = 1L;
    
    // 类的自有属性
    private String id;
    private String name;
    
    // 不需要序列化的属性加transient关键字修饰
    private transient String tempField;
    
    // getter、setter省略
}

2 配置Redis客户端序列化规则

如果使用Spring Data Redis,需要将value的序列化器设置为字节数组/JDK序列化器,不要使用默认的String序列化器,避免字节编码损坏:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        // key使用String序列化器,方便直接查看
        template.setKeySerializer(new StringRedisSerializer());
        // value使用JDK序列化器,直接操作字节数组
        template.setValueSerializer(new JdkSerializationRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
}

3 修正后的存取方法

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.time.Duration;

// 存储对象到Redis
public boolean addToRedis(Object obj) {
    // 提前校验对象是否支持序列化
    if (!(obj instanceof Serializable)) {
        throw new IllegalArgumentException("待存储对象必须实现Serializable接口");
    }
    // 使用try-with-resources自动关闭流
    try (ByteArrayOutputStream out = new ByteArrayOutputStream();
         ObjectOutputStream os = new ObjectOutputStream(out)) {
        os.writeObject(obj);
        // 字符串统一使用双引号,key可以根据业务调整
        redis.set("ObjectKey", out.toByteArray(), Duration.ofSeconds(5000));
        return true;
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
}

// 从Redis读取对象
public SomeObject getObjectFromRedis() {
    // 直接获取原始字节数组,不要做任何字符串转换
    byte[] objBytes = redis.get("ObjectKey");
    if (objBytes == null || objBytes.length == 0) {
        return null;
    }
    try (ByteArrayInputStream in = new ByteArrayInputStream(objBytes);
         ObjectInputStream is = new ObjectInputStream(in)) {
        return (SomeObject) is.readObject();
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

常见异常排查

  • 反序列化报InvalidClassException:检查serialVersionUID是否一致,类的包路径、类名是否和序列化时完全相同
  • 字节损坏异常:检查Redis客户端的value序列化器是否为JdkSerializationRedisSerializer,读取时是否直接拿字节数组没有转字符串
  • 序列化时报NotSerializableException:检查类的所有非transient属性是否都支持序列化,实体类是否实现了Serializable接口

内容的提问来源于stack exchange,提问作者Nitesh Nandan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 05:15:01