重生之不起眼的文章2
思考问题
我们将数据同时保存在了 数据库 和 Redis 当中,如果数据库中的数据更新了,但 Redis 缓存中的数据没有更新。
当用户来访问数据的时候,最先访问的 Redis 缓存中的旧数据,这就导致与数据库的数据不一致!
这就需要我们使用 Redis 的缓存更新策略。
缓存更新策略,有哪些?
内存淘汰
使用 Redis 的内存淘汰机制,当内存中的数据越来越多,没有进行删除 或者 漏删除了,导致内存中的数据超过了设定的最大内存限制时,Redis 会启动开启内存淘汰机制,释放部分的数据。
一致性差,只有当数据超过了设定的最大内存限制才会释放部分的数据。
超时剔除
将数据缓存到 Redis 中的同时给数据设置过期时间,到期后自动删除 Redis 缓存中的数据。
一致性一般,如果设置的过期时间过长,在过期时间之内数据更新了,也会导致 Redis 缓存中的数据是旧数据。
主动更新
自己编写代码逻辑,主动的去更新数据,具体介绍和内容,往下看......
一致性好。
主动更新
初始引入 Redis 缓存
我们现在是将数据保存到了 数据库 和 Reids 中 [如下图]
思考问题
如果数据库中的数据更新了,但 Redis 未更新,就会出现数据不一致。
虽然上面提到了内存淘汰和超时剔除,但是还会存在一致性问题,所以需要让我们主动去更新缓存。
主动更新缓存
更新缓存+更新数据库
因为这是两个步骤,就可能引发第一个步骤成功第二个步骤失败的问题、同时成功但出现了并发的问题。
- 先更新缓存,后更新数据库?
- 如果缓存更新成功,但数据库更新失败,那么就会出现:缓存中是新数据,数据库中是旧数据。
- 当缓存的过期时间到了,才会读取数据库中的旧数据。
- 先更新数据库,后更新?
- 如果数据库更新成功,但缓存更新失败,那么就会出现:数据库中是新数据,缓存中是旧数据。
- 当缓存的过期时间到了,才会读取数据库中的新数据。
- 更新数据库和更新缓存同时成功,但加入了并发。
- 两个线程同时去更新 Redis 和 数据库,虽然更新 Redis 数据时,线程-A 先于 线程-B,但是更新数据库数据时,线程-B 先于 线程-A 的,导致 Redis 中的数据 与 数据库中的数据不一致。 [如下图]
说明:先执行【1】再执行【2】
所以更新缓存+更新数据库,这种方案不行,换一个方案!
更新数据库+删除缓存
用户读取数据时会先到 Redis 缓存中的读取,缓存中没有再去 数据库中读取,读取成功后会写入 Redis 缓存中。
所以我们可以更新数据库数据后,删除掉缓存中的数据,等到再次读取该数据的时候由数据库写入到缓存中。
这也是两个步骤,就可能引发第一个步骤成功第二个步骤失败的问题、同时成功但出现了并发的问题。
- 先删除缓存,后更新数据库?
- 如果缓存删除成功,但数据库更新失败,那么就会出现:缓存中没有数据,数据库中是旧数据。
- 当用户再次获取数据时,直接读取数据库中的旧数据,然后又写入到缓存中。
- 先更新数据库,后删除缓存?
- 如果数据库更新成功,但缓存删除失败,那么就会出现:数据库中是新数据,缓存中是旧数据。
- 只有缓存的过期时间到了,才会读取数据库中的新数据,否则会一直读取缓存中的旧数据。
- 先删除缓存,后更新数据库,这两步同时成功,但加入了并发。
- 两个线程:线程-A 修改数据、线程-B 读取数据
- 因为 线程-A 删除了缓存,线程-B 中途读取数据只能从数据库中读取,线程-A 写入新数据后,线程-B 将旧数据写入到缓存中。
- 先更新数据库,后删除缓存,这两步同时成功,但加入了并发。
但是,出现这种问题必须满足 3 个条件:
- 缓存失效
- 读取数据和更新数据,有了并发
- 更新数据库+删除缓存 所花费的时间 比 读取数据库+写入缓存 所花费的时间 短
第 3 个条件发送的概率极低,因为写数据库一般会"加锁",所花费的时间会比读取数据库时间长。
所以,选择"先更新数据库,后删除缓存",因为这种方案出现数据不一致的概率极低。
