当前位置: 首页 > news >正文

学习日报 20250929|缓存雪崩以及缓存穿透解决方案

1. 缓存雪崩解决方案(随机过期时间工具类 + 使用示例)

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Random;
import java.util.concurrent.TimeUnit;/*** 缓存工具类:解决缓存雪崩问题(随机过期时间)*/
@Component
public class CouponCacheUtil {private final RedisTemplate<String, Object> redisTemplate;// 随机数生成器:用于生成过期时间偏移量private static final Random RANDOM = new Random();// 基础过期时间(30分钟):可根据业务调整private static final int BASE_EXPIRE_MINUTES = 30;// 随机偏移范围(5-30分钟):避免缓存集中过期private static final int MIN_RANDOM_MINUTES = 5;private static final int MAX_RANDOM_MINUTES = 30;public CouponCacheUtil(RedisTemplate<String, Object> redisTemplate) {this.redisTemplate = redisTemplate;}/*** 生成随机过期时间(基础时间+随机偏移)* 解决缓存雪崩:避免大量缓存同时过期*/private int getRandomExpireMinutes() {// 生成5-30分钟的随机值int randomOffset = MIN_RANDOM_MINUTES + RANDOM.nextInt(MAX_RANDOM_MINUTES - MIN_RANDOM_MINUTES + 1);// 总过期时间 = 基础时间 + 随机偏移return BASE_EXPIRE_MINUTES + randomOffset;}/*** 存储用户优惠券到缓存(带随机过期时间)* @param userId 用户ID* @param couponId 优惠券ID* @param couponInfo 优惠券信息(对象)*/public void setUserCouponCache(Long userId, Long couponId, Object couponInfo) {// 缓存key格式:业务前缀+用户ID+优惠券ID(避免key冲突)String cacheKey = "coupon:user:" + userId + ":" + couponId;// 获取随机过期时间int expireMinutes = getRandomExpireMinutes();// 存入Redis并设置过期时间redisTemplate.opsForValue().set(cacheKey,couponInfo,expireMinutes,TimeUnit.MINUTES);}/*** 获取用户优惠券缓存*/public Object getUserCouponCache(Long userId, Long couponId) {String cacheKey = "coupon:user:" + userId + ":" + couponId;return redisTemplate.opsForValue().get(cacheKey);}
}

2. 缓存穿透解决方案(优惠券模板查询示例)

import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;/*** 优惠券模板服务:解决缓存穿透问题*/
@Service
public class CouponTemplateService {private final CacheManager cacheManager;private final CouponTemplateDao couponTemplateDao; // 数据库访问层// 缓存穿透标记:用于标记不存在的模板(避免重复查询DB)private static final String CACHE_PENETRATION_MARKER = "NOT_EXIST";// 无效标记的过期时间(10分钟):避免长期占用缓存private static final int MARKER_EXPIRE_MINUTES = 10;public CouponTemplateService(CacheManager cacheManager, CouponTemplateDao couponTemplateDao) {this.cacheManager = cacheManager;this.couponTemplateDao = couponTemplateDao;}/*** 批量查询优惠券模板(解决缓存穿透)* @param templateIds 模板ID列表*/public List<CouponTemplate> queryTemplateBatch(List<Long> templateIds) {// 1. 参数校验:过滤无效ID(如null/负数),避免恶意请求List<Long> validIds = templateIds.stream().filter(id -> id != null && id > 0).toList();if (validIds.isEmpty()) {return new ArrayList<>();}// 2. 从缓存获取数据(使用LoadingCache或Spring Cache)Cache templateCache = cacheManager.getCache("coupon:template");List<CouponTemplate> result = new ArrayList<>();List<Long> missIds = new ArrayList<>(); // 缓存未命中的IDfor (Long id : validIds) {Object cacheValue = templateCache.get(id);if (cacheValue == null) {// 缓存未命中,记录ID后续查DBmissIds.add(id);} else if (CACHE_PENETRATION_MARKER.equals(cacheValue)) {// 命中无效标记,跳过(不查DB)continue;} else {// 命中有效数据,加入结果result.add((CouponTemplate) cacheValue);}}// 3. 缓存未命中的ID查询DBif (!missIds.isEmpty()) {List<CouponTemplate> dbTemplates = couponTemplateDao.queryByIds(missIds);// 4. 处理DB查询结果:存在的存入缓存,不存在的设置无效标记for (Long id : missIds) {// 查找DB中是否存在该模板CouponTemplate template = dbTemplates.stream().filter(t -> Objects.equals(t.getId(), id)).findFirst().orElse(null);if (template != null) {// 存在:存入缓存(使用随机过期时间,复用上面的工具类)templateCache.put(id, template);result.add(template);} else {// 不存在:设置无效标记(短期过期),避免缓存穿透templateCache.put(id, CACHE_PENETRATION_MARKER);// 手动设置标记的过期时间(如果缓存支持)// 示例:redisTemplate.expire(key, MARKER_EXPIRE_MINUTES, TimeUnit.MINUTES);}}}return result;}
}

3. 缓存穿透解决方案(用户优惠券查询示例)

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;/*** 用户优惠券服务:解决缓存穿透问题*/
@Service
public class UserCouponService {private final RedisTemplate<String, Object> redisTemplate;private final UserCouponDao userCouponDao; // 数据库访问层private final CouponCacheUtil cacheUtil; // 复用上面的缓存工具类// 无效用户优惠券标记(如:-1表示不存在)private static final Long INVALID_COUPON_MARKER = -1L;public UserCouponService(RedisTemplate<String, Object> redisTemplate,UserCouponDao userCouponDao,CouponCacheUtil cacheUtil) {this.redisTemplate = redisTemplate;this.userCouponDao = userCouponDao;this.cacheUtil = cacheUtil;}/*** 查询用户是否拥有某优惠券(解决缓存穿透)* @param userId 用户ID(需校验合法性)* @param couponId 优惠券ID*/public boolean hasUserCoupon(Long userId, Long couponId) {// 1. 参数合法性校验:拦截无效用户ID(如null/负数)if (userId == null || userId <= 0 || couponId == null || couponId <= 0) {// 记录恶意请求日志(可选)return false;}// 2. 从缓存查询String cacheKey = "coupon:user:has:" + userId + ":" + couponId;Object cacheValue = redisTemplate.opsForValue().get(cacheKey);if (cacheValue != null) {// 缓存命中:判断是否为有效标记return !INVALID_COUPON_MARKER.equals(cacheValue);}// 3. 缓存未命中,查询DBboolean exists = userCouponDao.exists(userId, couponId);// 4. 结果存入缓存:存在则存true,不存在则存无效标记if (exists) {// 有效数据:用随机过期时间(复用工具类)cacheUtil.setUserCouponCache(userId, couponId, true);} else {// 无效数据:设置标记(短期过期)redisTemplate.opsForValue().set(cacheKey,INVALID_COUPON_MARKER,5, // 5分钟过期,避免长期缓存无效数据TimeUnit.MINUTES);}return exists;}
}

关键实现说明:

  1. 缓存雪崩:通过 CouponCacheUtil 生成随机过期时间(基础时间 + 5-30 分钟偏移),避免大量缓存同时失效。
  2. 缓存穿透
    • 对无效参数(如负数 ID)直接拦截,减少无效请求。
    • 对 DB 中不存在的数据,缓存 “无效标记”(如 "NOT_EXIST"),短期过期,避免重复查询 DB。
    • 结合业务场景区分有效 / 无效数据(如用户优惠券用 -1 标记不存在)。
  3. 代码复用:缓存工具类和过期时间策略可全局复用,减少冗余代码。
http://www.dtcms.com/a/425065.html

相关文章:

  • 济南行业网站开发wordpress主题chuxia
  • 殷氏科技网站建设工作室如何选择网站开发
  • 电影网站域名wordpress add_action do_action
  • 营销网站与企业网站的区别电商网站详细设计
  • 有哪些网站是织梦做的wordpress写接口
  • 织梦做企业网站apache安装WordPress
  • cdr可以做网站页面吗温岭网络推广公司
  • 微网站 html标点狗logo设计官网
  • 乐清站在哪网站建设价格与方案
  • 单位写材料素材网站营销建设网站
  • php5mysql网站开发实例精讲asp.net 4.0网站开发
  • 山东济铁工程建设集团有限公司网站wordpress树形导航菜单
  • 淘宝客导购网站建设房产信息网显示已备案
  • mq网站开发苏州公司建设网站
  • 建设企业网站目的深圳外贸网站建设服务哪家好
  • 扬中网站优化哪家好wordpress新建阅读量字段
  • 做汽车养护的网站网盟推广和搜索推广的区别
  • 最新手机网站推荐建设网站火车票预订
  • 吉安市建设局施工管理站网站wordpress字体编辑插件下载
  • 网站如何选择服务器做毕业设计哪个网站好
  • Cubic 5分钟定制专属Ubuntu
  • 网站建设初级教程发广告平台有哪些免费
  • 独立开发者如何通过 Toolify.ai 网站寻找新热词
  • 目标网站上做关键字布局网站大全全部免费
  • 安徽省通信建设管理局网站做网站图标的软件
  • 烟台网站建设seo中国服务器排名前十名
  • Load Balance
  • 【深入浅出PyTorch】--3.1.PyTorch组成模块1
  • 上海网站建设哪家强明光网站
  • 网站建设价格标准信息湖南岳阳新增本土确诊0例