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

Spring Boot Redis缓存JSON序列化读取失败:No session求助

问题分析与解决思路

这个报错的核心是JPA懒加载机制和JSON序列化/反序列化的冲突:

  • 用@Cacheable缓存带关联列表的实体时,JPA默认关联关系是懒加载(fetch = FetchType.LAZY),序列化JSON时关联列表只是未初始化的代理对象;
  • 从Redis反序列化读取缓存时,代理对象尝试初始化关联数据,但此时已经没有Hibernate Session上下文,直接抛出No session错误。

具体解决方案

1. 临时方案:改为急加载

把实体中关联列表的fetch属性改为FetchType.EAGER,查询时直接加载关联数据,序列化到Redis的是完整数据,反序列化时不会触发懒加载:

@OneToMany(fetch = FetchType.EAGER)
private List<Entity2> entityList;

注意:若关联数据量较大,会拖慢查询性能,仅适合小数据场景。

2. 推荐方案:序列化前手动加载懒加载数据

在Service层查询到实体后,先初始化关联列表再返回(@Cacheable会缓存方法返回值):

@Cacheable(value = "entity1Cache")
public Entity1 getEntity1ById(Long id) {
    Entity1 entity1 = entity1Repository.findById(id).orElse(null);
    if (entity1 != null) {
        Hibernate.initialize(entity1.getEntityList()); // 手动触发懒加载,加载关联数据
    }
    return entity1;
}

3. 优雅方案:配置Jackson自动处理Hibernate懒加载

添加Jackson的Hibernate支持依赖:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>

然后在Redis序列化配置中注册该模块,让Jackson序列化时自动处理懒加载代理:

@Configuration
public class RedisConfig {
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration() {
        ObjectMapper objectMapper = new ObjectMapper()
                .registerModule(new Hibernate5Module()); // 注册Hibernate模块,自动处理懒加载
        return RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(
                        new GenericJackson2JsonRedisSerializer(objectMapper)
                ));
    }
}

如果需要强制加载所有懒加载数据,可以给模块添加配置:new Hibernate5Module().enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING)

4. 最佳实践:缓存DTO而非JPA实体

定义只包含业务所需字段的DTO(数据传输对象),查询后将实体转换为DTO再缓存,彻底规避懒加载问题:

// DTO类
public class Entity1DTO {
    private Long id;
    private String name;
    private List<Entity2DTO> entityList;
    // getter、setter、构造方法
}

// Service层代码
@Cacheable(value = "entity1Cache")
public Entity1DTO getEntity1DTOById(Long id) {
    Entity1 entity1 = entity1Repository.findById(id).orElse(null);
    if (entity1 == null) return null;
    
    // 实体转DTO(可使用MapStruct等工具简化转换逻辑)
    Entity1DTO dto = new Entity1DTO();
    dto.setId(entity1.getId());
    dto.setName(entity1.getName());
    dto.setEntityList(entity1.getEntityList().stream()
            .map(e2 -> {
                Entity2DTO e2Dto = new Entity2DTO();
                e2Dto.setId(e2.getId());
                e2Dto.setContent(e2.getContent());
                return e2Dto;
            }).collect(Collectors.toList()));
    return dto;
}

5. 检查Redis序列化配置

确保Redis使用正确的JSON序列化器,示例配置:

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(jsonSerializer);
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jsonSerializer);
        return template;
    }

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .build();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 12:15:40