spring boot 全局异常处理无法直接捕获缓存雪崩,因为缓存雪崩是业务逻辑层面的并发现象而非运行时异常。要解决这个问题,需要在访问缓存的代码层进行拦截,通过判断返回结果是否为空或超时来识别雪崩,并触发限流或降级逻辑,最终由全局异常处理器统一返回标准化的错误响应。

如何区分缓存穿透与缓存雪崩
缓存穿透是指查询不存在的数据,导致请求直达数据库;而缓存雪崩是指大量缓存键在同一时刻失效,引发高并发请求涌向数据库。在代码实现中,可以通过检查返回值是否为 null 且数据库中也无数据来辅助判断穿透,但雪崩通常表现为短时间内数据库连接池耗尽或响应时间急剧上升。为了准确区分,可以在 Service 层记录日志,当发现连续多次查询结果为空且伴随高并发时,标记为雪崩风险。

import org.springframework.stereotype.Service;
@Service
public class CacheService {
public Object getData(String key) {
// 模拟从缓存获取
Object cacheData = getFromCache(key);
if (cacheData != null) {
return cacheData;
}
// 模拟从数据库获取
Object dbData = getFromDB(key);
if (dbData == null) {
throw new RuntimeException("Data not found");
}
putToCache(key, dbData);
return dbData;
}
}
如何在 Controller 层统一处理业务异常
在 Controller 层,应当将具体的业务异常抛出,交由全局异常处理器捕获。对于缓存雪崩导致的数据库压力过大,可以自定义一个 CacheAvalancheException,并在 Service 层检测到并发高峰时抛出。全局异常处理器通过 @ExceptionHandler 注解捕获该异常,返回统一的 JSON 格式错误信息,避免直接暴露堆栈跟踪给前端用户。

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(CacheAvalancheException.class)
public ResponseEntity<string> handleCacheAvalanche(CacheAvalancheException ex) {
return ResponseEntity.status(503).body("Service temporarily unavailable due to cache avalanche");
}
}</string>
基于 Redis 缓存键过期时间的具体问题分析
如果所有缓存键都设置了相同的过期时间,例如都在 1 小时后过期,那么在这一时刻会有大量请求同时到达数据库,导致雪崩。为了避免这种情况,可以为每个缓存键添加随机偏移量,使得它们的过期时间分散开来。例如,设置过期时间为 1 小时加上 0 到 10 分钟的随机值,这样可以有效降低同时失效的概率,从而减轻数据库的压力。











