IT评测·应用市场-qidao123.com技术社区

标题: Redis+Caffeine多级缓存架构代码实战 [打印本页]

作者: 羊蹓狼    时间: 2025-4-12 09:51
标题: Redis+Caffeine多级缓存架构代码实战
  1. private final Cache<String, String> LOCAL_CACHE = Caffeine.newBuilder()
  2.             .initialCapacity(1024)
  3.             .maximumSize(10_000L) // 最大 10000 条
  4.             // 缓存 5 分钟后移除
  5.             .expireAfterWrite(Duration.ofMinutes(5))
  6.             .build();
复制代码
Caffeine 简介

Caffeine 是一个高性能、轻量级的本地缓存库,紧张用于 Java 应用中,用来替代像 Guava Cache 更高效的实现。下面是对 Caffeine 及其用法的快速概述:
  1.      // 存数据
  2.      LOCAL_CACHE.put("user:1", "Alice");
  3.      
  4.      // 取数据
  5.      String value = LOCAL_CACHE.getIfPresent("user:1");
复制代码
  1. /**
  2.      * 分页获取图片列表(封装类,有缓存)
  3.      */
  4.     @Deprecated
  5.     @PostMapping("/list/page/vo/cache")
  6.     public BaseResponse<Page<PictureVO>> listPictureVOByPageWithCache(@RequestBody PictureQueryRequest pictureQueryRequest,HttpServletRequest request) {
  7.         long current = pictureQueryRequest.getCurrent();
  8.         long size = pictureQueryRequest.getPageSize();
  9.         // 限制爬虫
  10.         ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
  11.         // 普通用户默认只能看到审核通过的数据
  12.         pictureQueryRequest.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
  13.         // 查询缓存,缓存中没有,再查询数据库
  14.         // 构建缓存的 key
  15.         String queryCondition = JSONUtil.toJsonStr(pictureQueryRequest);
  16.         String hashKey = DigestUtils.md5DigestAsHex(queryCondition.getBytes());
  17.         String cacheKey = String.format("listPictureVOByPage:%s", hashKey);
  18.         // 1. 先从本地缓存中查询
  19.         String cachedValue = LOCAL_CACHE.getIfPresent(cacheKey);
  20.         if (cachedValue != null) {
  21.             // 如果缓存命中,返回结果
  22.             Page<PictureVO> cachedPage = JSONUtil.toBean(cachedValue, Page.class);
  23.             return ResultUtils.success(cachedPage);
  24.         }
  25.         // 2. 本地缓存未命中,查询 Redis 分布式缓存
  26.         ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
  27.         cachedValue = opsForValue.get(cacheKey);
  28.         if (cachedValue != null) {
  29.             // 如果缓存命中,更新本地缓存,返回结果
  30.             LOCAL_CACHE.put(cacheKey, cachedValue);
  31.             Page<PictureVO> cachedPage = JSONUtil.toBean(cachedValue, Page.class);
  32.             return ResultUtils.success(cachedPage);
  33.         }
  34.         // 3. 查询数据库
  35.         Page<Picture> picturePage = pictureApplicationService.page(new Page<>(current, size),
  36.                 pictureApplicationService.getQueryWrapper(pictureQueryRequest));
  37.         Page<PictureVO> pictureVOPage = pictureApplicationService.getPictureVOPage(picturePage, request);
  38.         // 4. 更新缓存
  39.         // 更新 Redis 缓存
  40.         String cacheValue = JSONUtil.toJsonStr(pictureVOPage);
  41.         // 设置缓存的过期时间,5 - 10 分钟过期,防止缓存雪崩
  42.         int cacheExpireTime = 300 + RandomUtil.randomInt(0, 300);
  43.         opsForValue.set(cacheKey, cacheValue, cacheExpireTime, TimeUnit.SECONDS);
  44.         // 写入本地缓存
  45.         LOCAL_CACHE.put(cacheKey, cacheValue);
  46.         // 获取封装类
  47.         return ResultUtils.success(pictureVOPage);
  48.     }
复制代码
下面是对该代码中接纳缓存策略的详细阐述:

1. 方法的基本职责

该方法紧张用于分页获取图片列表,并对查询效果进行缓存。返回效果为一个封装了分页数据(PictureVO 对象列表)的响应。

2. 参数及校验



3. 构建缓存 Key



4. 两级缓存策略



4.1. 一级缓存——本地缓存(Caffeine)


4.2. 二级缓存——Redis 分布式缓存



5. 数据库查询与缓存更新

当两级缓存都未命中时,实行数据库查询并更新缓存:


6. 防止缓存雪崩与缓存穿透



7. 总结



这种双缓存策略属于常见的“先查询本地缓存,再查询分布式缓存,末了查询数据库,更新缓存”的应用场景,实用于高并发系统中对响应时间和数据同等性要求较高的场景。
注意

缓存中存储的是通过 JSONUtil.toJsonStr(pictureVOPage) 序列化后的 JSON 字符串,而这个过程往往会将对象中默认值、null 值大概部门未被标记为必要序列化的数据过滤掉,从而使数据量变小。
而直接从数据库查询得到的对象(或经过业务转换的对象)大概包罗更多的字段(比如额外的分页元数据、内部状态或调试信息等),这些数据在序列化时假如不做处置惩罚,大概会被完整返回。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4