其实对于读缓存的流程而言 , 大家一般都没什么异议 , 有异议的主要是写流程 , 我们继续来看 。
2.2 写缓存先来看一张流程图:
这个写缓存的流程就比较简单 , 先更新数据库中的数据 , 然后删除旧的缓存即可 。
流程虽然简单 , 但是却引伸出来两个问题:
- 为什么是删除旧缓存而不是更新旧缓存?
- 为什么不先删除旧的缓存 , 然后再更新数据库?
为什么是删除旧缓存而不是更新旧缓存?
- 更新缓存 , 说着容易做起来并不容易 。 很多时候我们更新缓存并不是简简单单更新一个 Bean 。 很多时候 , 我们缓存的都是一些复杂操作或者计算(例如大量联表操作、一些分组计算)的结果 , 如果不加缓存 , 不但无法满足高并发量 , 同时也会给 MySQL 数据库带来巨大的负担 。 那么对于这样的缓存 , 更新起来实际上并不容易 , 此时选择删除缓存效果会更好一些 。
- 对于一些写频繁的应用 , 如果按照更新缓存->更新数据库的模式来 , 比较浪费性能 , 因为首先写缓存很麻烦 , 其次每次都要写缓存 , 但是可能写了十次 , 只读了一次 , 读的时候读到的缓存数据是第十次的 , 前面九次写缓存都是无效的 , 对于这种情况不如采取先写数据库再删除缓存的策略 。
- 在多线程环境下 , 这样的更新策略还有可能会导致数据逻辑错误 , 来看如下一张流程图:
可以看到 , 有两个并发的线程 A 和 B:
- 首先 A 线程更新了数据库 。
- 接下来 B 线程更新了数据库 。
- 由于网络等原因 , B 线程先更新了缓存 。
- A 线程更新了缓存 。
为什么不先删除旧的缓存 , 然后再更新数据库?这个也是考虑到并发请求 , 假设我们先删除旧的缓存 , 然后再更新数据库 , 那么就有可能出现如下这种情况:
这个操作是这样的 , 有两个线程 , A 和 B , 其中 A 写数据 , B 读数据 , 具体流程如下:
- A 线程首先删除缓存 。
- B 线程读取缓存 , 发现缓存中没有数据 。
- B 线程读取数据库 。
- B 线程将从数据库中读取到的数据写入缓存 。
- A 线程更新数据库 。
2.3 延迟双删其实无论是先更新数据库再删除缓存 , 还是先删除缓存再更新数据库 , 在并发环境下都有可能存在问题:
假设有 A、B 两个并发请求:
- 先更新数据库再删除缓存:当请求 A 更新数据库之后 , 还未来得及进行缓存清除 , 此时请求 B 查询到并使用了 Cache 中的旧数据 。
- 先删除缓存再更新数据库:当请求 A 执行清除缓存后 , 还未进行数据库更新 , 此时请求 B 进行查询 , 查到了旧数据并写入了 Cache 。
- 创投圈|抖音小店无货源适合新手小白么?如何精细化运营?新手小白看来
- 松下|淘宝店铺信誉分等级如何提升?
- PHP|如何降低用户关注的非必要页面的权重传递?
- 量子纠缠存在于任何维度空间?人类如何逃出三维空间变成“神”?
- 显卡|如何组装旗舰游戏电脑?这里有你想要的答案
- 火星和地球交换位置会如何?火星会出现生命吗?答案没你想得简单
- 快手视频|视频号和抖音快手的差异化在哪里呢?你应该如何选择适合你的平台
- AirPods|如何进行微信活动运营才有效?
- 酷睿处理器|AMD Zen4如何接招?13代酷睿Z790主板偷跑:DDR4内存还在
- 蓝牙AOA定位那点事系列085:如何应对第一次合作软件开发合作伙伴的问题和需求
