其实对于读缓存的流程而言 , 大家一般都没什么异议 , 有异议的主要是写流程 , 我们继续来看 。
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 。
- 互联网家装|骑手、用户、商家的「不可能三角」,美团如何平衡?
- OPPO Find X5 Pro夜景表现如何?自研芯片真有疗效?
- 3D打印|做自媒体如何找到自己的定位?调研先行
- 老板娘|电商三巨头业绩出炉,拼多多净利润77亿,阿里1432亿,京东如何
- 裁员|后疫情时代,企业如何做好数字化转型布局线上流量
- 华为手机|外媒是如何报道国产华为手机的?
- 网易云音乐|“后跨界时代”,空天企业如何与大厂共处? | 深度
- OLED|全球首款120Hz OLED笔记本实际体验如何?看看知乎大V给出的参考
- 石墨烯|315信息安全实验室、个人信息保护大势来袭,品牌如何精准营销?
- 自媒体|自媒体剪辑真的能挣钱吗?该如何做好自媒体呢?