Spring Data Redis读取含AtomicInteger缓存抛出类型转换异常如何解决?
错误根因
Spring Data Redis 默认的类型转换体系没有内置 byte[]/String 到 AtomicInteger 的转换逻辑:你写入缓存时 AtomicInteger 类型的 rate 字段会被序列化为普通数值字符串,读取时框架无法直接把数值字符串映射回 AtomicInteger 类型,因此抛出转换异常。
解决方案
方案1:调整字段类型(改动最小,适合低并发场景)
直接把实体类中的AtomicInteger字段改为Integer,仅在需要原子操作时转换为AtomicInteger处理:
@RedisHash(value = "ThottleRate", timeToLive = 5) public class ThottleRate implements Serializable { private static final long serialVersionUID = 1L; @Id private String url; // 改为Integer适配默认序列化规则 private Integer rate; public ThottleRate(String url, int rate) { super(); this.url = url; this.rate = rate; } public boolean isAllowed(){ AtomicInteger atomicRate = new AtomicInteger(this.rate); int current = atomicRate.decrementAndGet(); this.rate = current; return current > 0; } }
注意:该方案的读-改-写逻辑存在并发安全问题,仅适合并发量不高的场景。
方案2:自定义类型转换器(保留原有字段定义,零业务逻辑改动)
自定义两个转换器处理AtomicInteger和String的互转,注册到Spring Data Redis的转换体系即可:
- 定义转换器类:
import org.springframework.core.convert.converter.Converter; import java.util.concurrent.atomic.AtomicInteger; // 读取缓存时用:String转AtomicInteger public class StringToAtomicIntegerConverter implements Converter<String, AtomicInteger> { @Override public AtomicInteger convert(String source) { return new AtomicInteger(Integer.parseInt(source)); } } // 写入缓存时用:AtomicInteger转String public class AtomicIntegerToStringConverter implements Converter<AtomicInteger, String> { @Override public String convert(AtomicInteger source) { return source.toString(); } }
- 注册转换器到Redis配置:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.core.convert.RedisCustomConversions; import java.util.Arrays; @Configuration public class RedisConfig { @Bean public RedisCustomConversions redisCustomConversions() { return new RedisCustomConversions(Arrays.asList( new StringToAtomicIntegerConverter(), new AtomicIntegerToStringConverter() )); } }
方案3:配置支持原子类的序列化器
使用Jackson序列化器并注册JDK类型支持模块,直接适配AtomicInteger等原子类的序列化:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; @Configuration public class RedisSerializerConfig { @Bean public RedisSerializer<Object> redisSerializer() { ObjectMapper objectMapper = new ObjectMapper(); // 注册JDK扩展类型模块,内置Atomic系列类的序列化逻辑 objectMapper.registerModule(new JavaTimeModule()); return new GenericJackson2JsonRedisSerializer(objectMapper); } }
可选优化
如果追求更高的限流性能和并发安全性,建议直接使用Redis原生的INCR+EXPIRE命令实现限流,无需定义实体类存储,性能更优且天然原子性。
内容的提问来源于stack exchange,提问作者Anton Cavanaugh
相关产品推荐
相关产品推荐

