
Redis 作为后端开发最常用的缓存组件几乎所有项目都会用到SpringBoot 整合 Redis 看似简单但实际开发中各种报错层出不穷卡壳半天✅ 连接 Redis 失败报 Could not get a resource from the pool ✅ 缓存序列化报错Cannot deserialize value of type XXX ✅ 操作 Redis 报 NoSuchKeyExceptionkey 存在却查不到 ✅ 缓存过期策略失效key 一直存在不删除 ✅ 分布式锁报错死锁、锁失效导致并发问题。今天这篇把 SpringBoot 整合 Redis 的6大高频报错一次性讲透结合缓存实战场景每个报错都给「报错信息根因分析解决方案可复制代码」从基础连接到进阶缓存操作、分布式锁全覆盖新手也能轻松避坑建议收藏缓存开发时直接查一、先搞懂Redis 报错核心逻辑SpringBoot 整合 Redis 报错本质围绕「连接」「序列化」「缓存操作」「配置」四大核心常见问题方向连接问题Redis 服务未启动、地址/端口/密码错误、连接池配置不合理序列化问题未配置自定义序列化默认 JDK 序列化导致数据乱码、反序列化失败操作问题key 不存在、数据类型不匹配、缓存过期配置错误进阶问题分布式锁使用不当、缓存穿透/击穿/雪崩、Redis 集群配置错误。排查优先级先确保 Redis 服务正常 → 再检查连接配置 → 然后排查序列化 → 最后处理缓存操作和进阶问题高效定位少走弯路。二、6大高频 Redis 报错场景解决方案按出现概率排序场景1最经典——Redis 连接失败报 Could not get a resource from the pool1. 典型报错信息org.springframework.data.redis.RedisConnectionFailureException: Could not get a resource from the pool; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to localhost:63792. 错误原因4种高频情况Redis 服务未启动或启动失败核心原因Redis 连接配置错误IP、端口写错默认端口6379Redis 开启了密码认证配置中未填写密码或密码错误Redis 连接池配置不合理最大连接数不足、超时时间过短导致连接耗尽。3. 解决方案按排查顺序启动 Redis 服务验证是否正常运行 Windows双击 redis-server.exe Linuxredis-server /etc/redis/redis.conf 执行命令redis-cli ping返回 PONG 即为正常。检查 SpringBoot Redis 连接配置application.yml若 Redis 开启密码添加密码配置优化连接池配置避免连接耗尽。# 正确配置 Redis 连接含连接池 spring: redis: host: localhost # Redis 服务IP远程服务器填公网IP port: 6379 # 默认端口若修改需对应 password: 123456 # 若Redis未设密码可省略生产环境建议设密码 timeout: 5000 # 连接超时时间毫秒 lettuce: # 连接池配置SpringBoot 2.x 默认使用 lettuce替代 jedis pool: max-active: 100 # 最大连接数 max-idle: 20 # 最大空闲连接 min-idle: 5 # 最小空闲连接 max-wait: 3000 # 最大等待时间毫秒补充若远程连接 Redis需开放 6379 端口防火墙/云服务器安全组并修改 Redis 配置文件 redis.conf将 bind 127.0.0.1 改为 0.0.0.0允许远程连接。场景2最头疼——序列化报错Cannot deserialize value of type XXX1. 典型报错信息org.springframework.data.redis.serializer.SerializationException: Cannot deserialize value of type com.xxx.entity.User from Binary data (byte[]): could not deserialize using [org.springframework.data.redis.serializer.JdkSerializationRedisSerializer]2. 错误原因2种高频情况未配置自定义序列化SpringBoot 默认使用 JDK 序列化导致缓存数据乱码、反序列化失败实体类未实现 Serializable 接口或序列化版本号不一致导致反序列化失败。3. 解决方案推荐使用 Jackson 序列化避免乱码方案1配置 Redis 自定义序列化核心复制即用Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Objectgt; redisTemplate new RedisTemplate(); redisTemplate.setConnectionFactory(factory); // 配置 Jackson 序列化 Jackson2JsonRedisSerializerObjectgt; jacksonSerializer new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper new ObjectMapper(); // 开启实体类和JSON的字段映射 objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 开启反序列化时识别子类 objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); jacksonSerializer.setObjectMapper(objectMapper); // 配置 String 序列化key 用 String 序列化 StringRedisSerializer stringSerializer new StringRedisSerializer(); // key 序列化方式 redisTemplate.setKeySerializer(stringSerializer); // value 序列化方式 redisTemplate.setValueSerializer(jacksonSerializer); // hash key 序列化方式 redisTemplate.setHashKeySerializer(stringSerializer); // hash value 序列化方式 redisTemplate.setHashValueSerializer(jacksonSerializer); // 初始化 RedisTemplate redisTemplate.afterPropertiesSet(); return redisTemplate; } }方案2实体类实现 Serializable 接口// 实体类必须实现 Serializable 接口否则序列化失败 public class User implements Serializable { private static final long serialVersionUID 1L; // 序列化版本号避免版本不一致报错 private Long id; private String username; private Integer age; // getter/setter 省略 }补充若使用 Cacheable 注解实现缓存需额外配置缓存管理器确保缓存序列化一致代码见场景3补充。场景3缓存操作报错NoSuchKeyExceptionkey 存在却查不到1. 典型报错信息io.lettuce.core.RedisCommandExecutionException: NO such key2. 错误原因3种高频情况key 拼写错误大小写敏感如 key 是 user:1查询时写 user:2序列化方式不一致如存入时用 Jackson 序列化查询时用 JDK 序列化导致 key 不匹配缓存过期key 已被 Redis 自动删除或手动删除后未重新存入。3. 解决方案Service public class UserService { Autowired private RedisTemplateString, Object redisTemplate; public User getUserById(Long id) { String key user: id; // 统一 key 命名规范避免拼写错误 // 1. 先查缓存 User user (User) redisTemplate.opsForValue().get(key); if (user ! null) { return user; } // 2. 缓存未命中查数据库 user userMapper.selectById(id); if (user ! null) { // 3. 存入缓存设置过期时间避免缓存雪崩 redisTemplate.opsForValue().set(key, user, 30, TimeUnit.MINUTES); } return user; } }补充若使用 Cacheable 注解需配置缓存管理器确保序列化一致// 在 RedisConfig 中添加缓存管理器配置 Bean public CacheManager cacheManager(RedisConnectionFactory factory) { // 配置缓存过期时间 RedisCacheConfiguration config RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(30)) // 全局缓存过期时间30分钟 .serializeKeysWith(RedisSerializationContext.SerializationPair .fromSerializer(new StringRedisSerializer())) // key 序列化 .serializeValuesWith(RedisSerializationContext.SerializationPair .fromSerializer(new GenericJackson2JsonRedisSerializer())) // value 序列化 .disableCachingNullValues(); // 禁止缓存 null 值 // 初始化缓存管理器 return RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); } // 使用 Cacheable 注解自动缓存无需手动操作 redisTemplate Cacheable(value user, key #id) // 缓存keyuser::id public User getUserById(Long id) { return userMapper.selectById(id); }场景4缓存过期策略失效key 一直存在不删除1. 典型现象给 Redis key 设置了过期时间如 30 分钟但过了过期时间key 依然存在未被自动删除导致缓存数据过时、占用 Redis 内存。2. 错误原因3种高频情况设置过期时间时时间单位错误如把秒当成毫秒30 秒写成 30实际过期时间 30 毫秒瞬间过期或反之对已存在的 key 重新赋值时未重新设置过期时间导致过期时间被清除Redis 开启了持久化RDB/AOF重启 Redis 后过期 key 被恢复且过期时间丢失。3. 解决方案// 1. 正确设置过期时间指定时间单位 String key user:1; // 正确30分钟过期TimeUnit.MINUTES redisTemplate.opsForValue().set(key, user, 30, TimeUnit.MINUTES); // 错误未指定时间单位默认毫秒30毫秒过期几乎瞬间失效 // redisTemplate.opsForValue().set(key, user, 30); // 2. 重新赋值时重新设置过期时间 redisTemplate.opsForValue().set(key, newUser, 30, TimeUnit.MINUTES); // 3. 给已存在的 key 单独设置过期时间 if (redisTemplate.hasKey(key)) { redisTemplate.expire(key, 30, TimeUnit.MINUTES); } // 4. 持久化配置优化避免过期key恢复 # application.yml 配置 spring: redis: lettuce: pool: # 其他配置省略 # 开启 AOF 持久化推荐避免过期key恢复 appendonly: true # 配置 AOF 重写策略减少内存占用 appendfilename: appendonly.aof aof: rewrite-incremental-fsync: true场景5分布式锁报错死锁、锁失效1. 典型报错信息// 死锁锁未释放其他线程无法获取锁 java.lang.RuntimeException: 获取分布式锁失败超时 // 锁失效锁提前过期导致并发修改数据 java.lang.RuntimeException: 数据被并发修改出现脏数据2. 错误原因死锁获取锁后程序异常退出、未释放锁且锁未设置过期时间导致锁一直存在锁失效锁过期时间设置过短任务未执行完成锁已过期其他线程获取到锁导致并发问题未使用原子操作获取/释放锁导致锁竞争异常。3. 解决方案使用 Redis 分布式锁避免死锁和失效Service public class DistributedLockService { Autowired private StringRedisTemplate stringRedisTemplate; // 锁的前缀避免key冲突 private static final String LOCK_PREFIX lock:; // 锁的过期时间默认30秒根据任务执行时间调整 private static final long LOCK_EXPIRE 30; // 获取锁的超时时间默认5秒避免一直阻塞 private static final long ACQUIRE_TIMEOUT 5; // 获取分布式锁 public boolean acquireLock(String lockKey) { String key LOCK_PREFIX lockKey; long end System.currentTimeMillis() ACQUIRE_TIMEOUT * 1000; // 循环获取锁超时则放弃 while (System.currentTimeMillis() end) { // 原子操作setnx expire避免死锁 Boolean success stringRedisTemplate.opsForValue() .setIfAbsent(key, 1, LOCK_EXPIRE, TimeUnit.SECONDS); if (Boolean.TRUE.equals(success)) { return true; // 获取锁成功 } try { Thread.sleep(100); // 休眠100毫秒避免频繁竞争 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } return false; // 获取锁失败 } // 释放分布式锁必须确保只有持有锁的线程能释放 public void releaseLock(String lockKey) { String key LOCK_PREFIX lockKey; // 原子操作删除锁避免误删其他线程的锁 stringRedisTemplate.delete(key); } // 实战使用try-finally 确保锁释放 public void doBusiness(String lockKey) { try { // 获取锁 boolean hasLock acquireLock(lockKey); if (!hasLock) { throw new RuntimeException(获取分布式锁失败超时); } // 执行业务逻辑如修改库存、下单等 System.out.println(执行业务逻辑...); } finally { // 释放锁无论业务是否成功都要释放 releaseLock(lockKey); } } }补充生产环境推荐使用 Redisson 框架实现分布式锁自动处理锁过期、重入、释放等问题简化开发。场景6Redis 数据类型不匹配报 WRONGTYPE Operation against a key holding the wrong kind of value1. 典型报错信息io.lettuce.core.RedisCommandExecutionException: WRONGTYPE Operation against a key holding the wrong kind of value2. 错误原因Redis 中同一个 key 被存储为不同的数据类型如先存储为 String 类型再用 Hash 操作该 key导致操作时数据类型不匹配报错。3. 解决方案统一 key 命名规范给不同数据类型的 key 加前缀如 string:user:1、hash:order:1避免 key 冲突操作 key 前先判断数据类型再执行对应操作若 key 类型错误删除该 key 后重新存入正确类型的数据。// 正确示例不同类型 key 加前缀避免冲突 // String 类型 stringRedisTemplate.opsForValue().set(string:user:1, 张三); // Hash 类型 stringRedisTemplate.opsForHash().put(hash:order:1, orderNo, 20260317001); // 操作前判断数据类型 String key string:user:1; if (stringRedisTemplate.hasKey(key)) { // 判断 key 的数据类型 String type stringRedisTemplate.type(key).code(); if (string.equals(type)) { // 执行 String 类型操作 String value stringRedisTemplate.opsForValue().get(key); } else { log.error(key {} 的数据类型为 {}无法执行 String 操作, key, type); } }三、Redis 万能排查步骤记这6步查服务Redis 服务是否启动执行 ping 命令验证是否正常查连接IP、端口、密码是否正确连接池配置是否合理端口是否开放查序列化是否配置自定义序列化实体类是否实现 Serializable 接口查 keykey 拼写是否正确、大小写是否一致数据类型是否匹配查过期key 过期时间是否设置正确重新赋值是否重置过期时间查进阶分布式锁是否正确释放缓存策略是否避免穿透/击穿/雪崩。四、避坑指南Redis 开发必看连接配置生产环境必须设置 Redis 密码远程连接需开放端口、修改 bind 配置连接池参数根据并发量调整避免连接耗尽序列化优先使用 Jackson 序列化避免 JDK 序列化导致的乱码、反序列化失败实体类必须实现 Serializable 接口key 规范统一 key 命名给不同数据类型的 key 加前缀避免 key 冲突、类型不匹配过期策略所有缓存 key 必须设置过期时间避免缓存雪崩重新赋值时务必重置过期时间分布式锁避免手动实现复杂锁逻辑生产环境用 Redisson必须用 try-finally 确保锁释放避免死锁持久化生产环境开启 AOF 持久化避免 Redis 重启后数据丢失、过期 key 恢复。五、总结SpringBoot 整合 Redis 报错核心就4个问题「连接失败」「序列化错误」「key 操作不当」「进阶场景使用不规范」记住连接失败查服务、配置、端口、密码序列化错误配置 Jackson 序列化实体类实现 Serializablekey 问题查拼写、类型、过期时间分布式锁避免死锁和失效优先用 Redisson缓存策略设置过期时间避免穿透、击穿、雪崩。Redis 是后端缓存的核心只要配置正确、使用规范就能避免99%的报错。掌握本文的场景和解决方案缓存开发时能快速定位 Redis 相关问题高效解决让缓存稳定发挥作用提升服务性能。如果这篇文章帮到你了记得点赞收藏评论区说说你遇到过最坑的 Redis 问题一起交流避坑经验