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

Spring Boot向Redis存储数据时出现StackOverflowError求助

Spring Boot Redis保存时StackOverflowError排查与解决建议

来帮你拆解这个Spring Boot存Redis时触发的StackOverflowError问题!从你贴的代码和堆栈信息来看,核心问题肯定是序列化时的无限递归,大概率和对象的循环引用有关,下面是具体的排查思路和解决办法:

问题核心分析

从异常堆栈能看到,MappingRedisConverter在反复调用writeInternal和writeCollection,这明显是序列化过程中陷入了无限循环。结合你的RedisObj里有MyObject field9这个嵌套对象,几乎可以确定:MyObject内部要么引用了RedisObj,要么存在自引用(比如List<MyObject>类型的字段),导致Spring Data Redis在转换对象时不断递归处理,最终撑爆栈内存。

你的相关代码

RedisRepo接口

public interface RedisRepo extends CrudRepository<RedisEntity,String> { }

RedisObj实体类

public class RedisObj {
    @Id
    private Long field1;
    private String field2;
    private String field3;
    private String field4;
    private String field5;
    private UUID field6;
    private String field7;
    private String field8;
    private MyObject field9;
}

业务层调用代码

redisRepo.save(ObjToRedis);

关键异常堆栈片段

Caused by: java.lang.StackOverflowError: null
at org.springframework.core.convert.TypeDescriptor.getElementTypeDescriptor(TypeDescriptor.java:331) ~[spring-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.core.convert.TypeDescriptor.equals(TypeDescriptor.java:470) ~[spring-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
...
at org.springframework.data.redis.core.convert.MappingRedisConverter.writeInternal(MappingRedisConverter.java:583) ~[spring-data-redis-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.data.redis.core.convert.MappingRedisConverter.writeCollection(MappingRedisConverter.java:719) ~[spring-data-redis-2.1.5.RELEASE.jar:2.1.5.RELEASE]

排查步骤

  • 检查MyObject的结构:重点看MyObject是否有引用RedisObj的字段,或者存在自引用(比如private MyObject parent;或private List<MyObject> children;),这是递归的常见源头。
  • 验证对象转换逻辑:确认ObjToRedis是如何从业务对象转换而来的,转换过程中是否不小心创建了循环引用的结构。
  • 开启调试日志:在配置文件中添加日志配置,打印序列化的细节,精准定位递归的起点:
    logging.level.org.springframework.data.redis.core.convert=DEBUG
    

解决方案

根据不同的递归原因,有几种针对性的处理方式:

1. 直接打破循环引用

如果MyObject里确实有循环引用的字段,可以用注解告诉序列化工具忽略该字段:

public class MyObject {
    // 忽略循环引用的字段,避免递归序列化
    @JsonIgnore
    private RedisObj redisObj;
    
    // 其他字段...
}

或者用Spring Data Redis专属的注解:@RedisHash(ignore = true)

2. 配置序列化工具处理循环引用

如果需要保留引用关系,可以配置Jackson序列化器支持循环引用:

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(connectionFactory);
    
    Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
    ObjectMapper mapper = new ObjectMapper();
    // 开启循环引用检测,用对象ID标记避免递归
    mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    mapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
    serializer.setObjectMapper(mapper);
    
    template.setValueSerializer(serializer);
    template.setKeySerializer(new StringRedisSerializer());
    return template;
}

同时在循环引用的类上添加标记注解:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "field1")
public class RedisObj {
    // 字段...
}

3. 简化Redis存储对象

如果不需要嵌套对象的完整结构,可以拆分数据:只存储Redis业务需要的字段,把MyObject的必要属性扁平到RedisObj中,或者单独存储MyObject,用键关联的方式引用,避免复杂嵌套带来的序列化问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:22:02