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

Spring Boot从Java 8迁移至Java 17后无法反序列化Redis数据

问题分析

从报错信息里的字节内容(sr/com.ceb.shl.shlonline.model.content.Assessments)可以直接看出:Redis中存储的数据是Java原生序列化格式,而你当前Java17应用使用的GenericJackson2JsonRedisSerializer是JSON序列化器,两者格式不兼容,导致JSON解析失败。

原因是原Java8应用大概率使用了默认的JdkSerializationRedisSerializer写入数据,你迁移后更换了序列化方式,自然无法读取旧数据。

解决方案

提供两种可行方案,按需选择:

方案1:兼容新旧数据(推荐渐进式过渡)

自定义混合序列化器,优先用JSON解析新数据,失败则用JDK序列化器解析旧数据,同时新写入的数据统一用JSON格式:

  1. 实现混合序列化器:
public class HybridRedisSerializer implements RedisSerializer<Object> {
    private final GenericJackson2JsonRedisSerializer jsonSerializer;
    private final JdkSerializationRedisSerializer jdkSerializer;

    public HybridRedisSerializer(ObjectMapper objectMapper) {
        this.jsonSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);
        this.jdkSerializer = new JdkSerializationRedisSerializer();
    }

    @Override
    public byte[] serialize(Object o) throws SerializationException {
        // 新数据统一用JSON序列化
        return jsonSerializer.serialize(o);
    }

    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        try {
            // 先尝试JSON解析
            return jsonSerializer.deserialize(bytes);
        } catch (Exception e) {
            // JSON解析失败,降级用JDK序列化解析旧数据
            return jdkSerializer.deserialize(bytes);
        }
    }
}
  1. 修改RedisTemplate配置,替换为混合序列化器:
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(redisConnectionFactory);

    ObjectMapper objectMapper = objectMapper();
    HybridRedisSerializer hybridSerializer = new HybridRedisSerializer(objectMapper);

    redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setValueSerializer(hybridSerializer);
    redisTemplate.setHashKeySerializer(new StringRedisSerializer());
    redisTemplate.setHashValueSerializer(hybridSerializer);

    return redisTemplate;
}

// 保留原ObjectMapper配置
@Bean
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(),
            ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
    return mapper;
}

方案2:全量迁移旧数据到JSON格式

如果允许短暂停服或批量处理,可一次性将旧数据转换为JSON格式:

  1. 临时用JDK序列化器读取所有旧数据,再用JSON序列化器重新写入:
// 临时执行代码,完成后可删除
RedisTemplate<String, Object> tempRedisTemplate = new RedisTemplate<>();
tempRedisTemplate.setConnectionFactory(redisConnectionFactory);
tempRedisTemplate.setKeySerializer(new StringRedisSerializer());
tempRedisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
tempRedisTemplate.setHashKeySerializer(new StringRedisSerializer());
tempRedisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
tempRedisTemplate.afterPropertiesSet();

// 读取目标哈希表的所有数据
HashOperations<String, String, Object> tempHashOps = tempRedisTemplate.opsForHash();
String cacheKey = cacheKeys.getCacheAssessmentKey();
Map<String, Object> allOldData = tempHashOps.entries(cacheKey);

// 用你的新RedisTemplate重新写入(自动转为JSON格式)
yourNewRedisTemplate.opsForHash().putAll(cacheKey, allOldData);
  1. 数据迁移完成后,恢复原有的JSON序列化配置即可。
额外注意事项
  • 若使用方案1,需确保Assessments类在Java17中可正常序列化:添加serialVersionUID,避免类结构变化导致的反序列化失败:
public class Assessments implements Serializable {
    private static final long serialVersionUID = 1L;
    // 类属性与方法
}

内容的提问来源于stack exchange,提问作者Shashank Garg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:32:12