您的位置:首页 > 文旅 > 旅游 > 看b站视频软件24小时_网购最便宜的软件_seo优化专员招聘_关键词排名监控批量查询

看b站视频软件24小时_网购最便宜的软件_seo优化专员招聘_关键词排名监控批量查询

2024/12/23 9:21:22 来源:https://blog.csdn.net/2202_75352238/article/details/142732699  浏览:    关键词:看b站视频软件24小时_网购最便宜的软件_seo优化专员招聘_关键词排名监控批量查询
看b站视频软件24小时_网购最便宜的软件_seo优化专员招聘_关键词排名监控批量查询

在分布式事务中我们知道有cap定理,即 我们保证高可用的情况下,必然要牺牲一些一致性,在保证强一致性的情况下,必然会牺牲一些可用性。而我们redis+mysql数据一致性的使用策略就是在我们保证可用性的情况下尽量保证数据的一致性。想要达到强一致性,不加锁,只用 一些缓存策略那必然不是不可能的

1.一般 查询的业务情况

我们常用的 情况有  对一些热点的数据,或者频繁的查询的数据,如果频繁访问数据库,必然会对数据库造成很大的压力,为了减缓这种压力,我们 用redis做缓存,数据库做底    我们的查询数据的情况一般如下

这样看似好像并没有什么问题,但是当我们想象这样一个业务场景

现在 我要对 该数据 A进行 修改,那么我们修改数据A之后,必然会要修改缓存 和数据库中的数据

那么问题来了,高并发的情况下,在修改数据的时候,如果来了一个查询操作,在这之间会怎么样呢?我们是先修改缓存数据,还是先修改数据库的数据呢?

我们要么先删除缓存 再修改数据库 ,要么先修改数据库再删除缓存,但是这两种情况都会出现 redis 和数据库 数据不一致的情况 

2.删除 缓存 +修改数据库

3.先修改数据库 再删除缓存

 所以综上所述  我们一般会采用 先修改数据库 然后再删除缓存,这也是 大家 选择的的比较多的方案

4.数据一致性兜底解决方案

先写库再删缓存”方案结合事务控制,能彻底保证缓存和数据库的一致性,但会极大程度损耗性能。而且对于业务操作来说,执行业务逻辑、更新库都没报错,偏偏走到最后删缓存时出错,因此需要将整个事务回滚,这是极不公平的  

 所以我们对删除缓存 进行一系列的 处理   

1. try catch  捕捉到 缓存删除失败,在catch中再次删除缓存,也就是 失败的话 重试多次

2. 延时双删  

1.删除缓存

2. 修改数据库

3.休眠 一段时间

4.再次删除缓存

3.异步处理  

这也是比较推荐的方案 

我们先 修改数据库,修改之后,使用mq 发送消息,然后由mq进行对缓存的删除,这样对业务代码侵入也比较低

5.缓存穿透解决

我们知道什么是缓存穿透,就是 请求 一个不存在的数据,然后 由于数据不存在,就不会加入到缓存,会一直访问数据库,这时候会对数据库造成非常大的压力  解决方案一般有两种

 布隆过滤器   和返回null 值  我们  这里只实现返回null值

 当我们 数据 在数据库查不到的时候,我们缓存一个空数据,为了防止内存浪费,我们给该空数据设置一个过期时间,这样 无论谁 用空数据 过度访问 ,都不会给数据库造成太大压力

我们以根据 商品 id 查询数据为例子,同时也对应我们 标题1 的业务实现

 

  @Overridepublic Result getByShopId(Long id) {//查缓存Map entriesMap = redisTemplate.opsForHash().entries(RedisConstants.CACHE_SHOP_KEY + id);if(StrUtil.isNotBlank((CharSequence) entriesMap.get("nullId"))){log.info(entriesMap.get("nullId").toString());log.info("店铺信息不存在");return Result.fail("店铺信息不存在");}// 有的话返回if(!entriesMap.isEmpty()){Shop shop = BeanUtil.fillBeanWithMap(entriesMap, new Shop(), false);log.info("缓存查询到了");return  Result.ok(shop);}//没有的话查数据库Shop shopById = query().eq("id", id).one();if(BeanUtil.isNotEmpty(shopById)){//数据库有的话 添加缓存并且返回Map<String, Object> stringObjectMap = BeanUtil.beanToMap(shopById);redisTemplate.opsForHash().putAll(RedisConstants.CACHE_SHOP_KEY + id,stringObjectMap);// 设置过期时间 防止内存 占满redisTemplate.expire(RedisConstants.CACHE_SHOP_KEY+id,RedisConstants.CACHE_SHOP_TTL,TimeUnit.MINUTES);return  Result.ok(shopById);}//数据库没有 返回false//解决缓存穿透   访问不存在的数据 缓存为null值 并且设置过期时间redisTemplate.opsForHash().put(RedisConstants.CACHE_SHOP_KEY+id,"nullId","null");redisTemplate.expire(RedisConstants.CACHE_SHOP_KEY+id,RedisConstants.CACHE_NULL_TTL, TimeUnit.SECONDS);return Result.ok("返回成功");}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com