这实际上这是一个如果想要答的完美,是非常难非常难的问题,所以差不多得了。
1.先更新redis,再更新mysql
2.先更新mysql,再更新Redis
3.先删除redis,再更新mysql(牛客论坛采用的就是这种方式)
4.先更新mysql,然后删除redis
5.redis订阅binlog日志
6.延时双删,先删除redis,然后更新mysql,然后再删除redis 这种方式就是在方式3的基础上最后再删除一次redis,怕更新mysql的操作有延迟,等更新mysql操作执行完,再删除redis
方案一,二,三,四都是假设第二步操作失败
缓存和数据库都更新:
方案一:先更新缓存,后更新数据库
如果缓存更新成功了,但数据库更新失败,那么此时缓存中是最新值,但数据库中是旧值
此时如果来了一个读请求 ,命中缓存,拿到正确的值,但是,一旦缓存「失效」,就会从数据库中读取到「旧值」,重新存入缓存的也是这个旧值
方案二:先更新数据库,然后再更新缓存
如果数据库更新成功了,但缓存更新失败,那么此时数据库中是最新值,缓存中是旧值。
请求读到的都是旧数据,只有当缓存「失效」后,才能从数据库中得到正确的值
删除缓存:
方案三:更新数据库前,先删除缓存,然后更新数据库,然后用户查询缓存的时候发现redis中没有要查的数据,于是去mysql中查,并且将查询到的数据缓存到redis里面
如果第二步操作失败,数据库更新不成功,那下次读缓存发现不存在,则从数据库中读取,并重建缓存,此时数据库和缓存里保存的都是旧值
方案四:先更新数据库,再删除缓存
如果第二步操作失败,数据库是最新值,缓存中是旧值,发生不一致
方案五: 订阅数据库变更日志binlog
只需修改数据库,不需要操作缓存
mysql数据库中有binlog日志,再将binlog日志放到消息队列上,redis根据这个binlog来更新自己的数据
方案六:延时双删(是在先删除缓存,再更新数据库的基础上再加一次删除)
考虑这种情况:删除了缓存之后,本来要去更新数据库的,此时由于网络原因卡顿了一下,没有去更新数据库,此时查询redis,发现redis里面没有数据,于是去数据库中查询数据,此时数据库没有被更新,所以查到的还是旧值,并且会把查到的旧值保存到redis中,此时,网络卡顿结束,更新数据库操作执行,把新值写入数据库,一段时间后,将缓存再次删除
总结:
先删除缓存
然后再更新数据库
休眠一段时间(比如1秒),再次删除缓存