🍖 Redis缓存中间件
🥩 缓存是什么
所谓缓存就是数据交换的缓冲区(称作Cache [ kæʃ ] ),是一个临时存贮数据的地方,一般读写性能较高。CPU的运算速度要远远大于内存的读写速度,这样会使CPU花费很长时间等待数据从内存的获取或者写入,因此缓存的出现主要就是为了解决CPU运算速度与内存读写速度不匹配的矛盾
说了半天缓存和web开发有什么必要的联系嘛?当然有,在整个web开发的各个阶段都可以使用到不同缓存,比如浏览器缓存页面等静态资源,tomcat服务器应用层缓存查询过的数据,数据库缓存索引信息等
缓存的优点
降低后端负载
提高读写效率,降低响应时间
缓存的缺点
数据更新前后缓存区中该数据的一致性难保证
解决数据一致性需要复杂的业务代码,提高后续维护成本
集群模式下提高运维成本
🥩 Redis缓存已查询数据
在未使用缓存之前,用户的所有请求都会直接访问数据库,但是使用redis作为缓存之后就不一样了。用户的请求会是先在redis中查找,如果查到也就是命中的话就直接返回客户端,如果未命中的话就去数据库中查找,查到有结果就将查询到的结果写入redis中,然后返回给客户端;未查到结果就返回404状态码
🥩 redis缓存中间件实践
黑马点评中有这么一个业务:点击商铺图片会通过id查询该商铺的相关信息,如果使用redis缓存的话,后期再访问该商铺的话就会直接到redis中查询,可以大大缩短查询所需时间
collector中定义与前端交互的方法,前端请求/shop-type/list?id=xx
@RestController @RequestMapping("/shop") public class ShopController { @Resource public IShopService shopService; /** * 根据id查询商铺信息 * @param id 商铺id * @return 商铺详情数据 */ @GetMapping("/{id}") public Result queryShopById(@PathVariable("id") Long id) { return shopService.queryById(id); } }
编写typeService里业务逻辑方法getList的接口和实现类,逻辑参考Redis缓存已查询数据的相关分析
@Service public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService { @Autowired private StringRedisTemplate stringRedisTemplate; @Override public Result queryById(Long id) { // 从redis查询商铺缓存 String shopJson = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + id); // 判断该商铺是否存在 if (StrUtil.isNotBlank(shopJson)) { // 存在直接返回 Shop shop = JSONUtil.toBean(shopJson, Shop.class); return Result.ok(shop); } // 不存在查询数据库 Shop shop = getById(id); if (shop == null) { // 数据库中不存在直接返回错误信息 return Result.fail("店铺不存在"); } // 数据库中存在写入redis stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(shop)); // 返回 return Result.ok(shop); } }
经实验验证得知,使用redis缓存未命中时查询耗时将近200毫秒,后续查询命中之后只需几毫秒,可见redis作为缓存中间件对数据读取的功效还是很高的
🍖 缓存更新
之前介绍redis的时候介绍过redis缓存的一些缺点,比如数据库中数据更新前后缓存区中该数据的一致性难保证,该怎么应对redis缓存的这个缺点呢?这就引出接下来的学习内容——缓存更新策略