一:项目中缓存是如何使用的?
项目中使用缓存保存医疗机构信息数据,将对象进行序列化是将对象转换成二进制流,从而可以将这个二进制流存储到Redis中,读取Redis中存储的数据并反序列化对象
二:为什么要用缓存?直接用 mysql也可以啊
用缓存,主要是高性能、高并发。
高性能:内存的读写速度远快于磁盘的读写速度,后面数据不怎么变化,并且有很多读请求,那么直接将查询出来的结果放在缓存中,后面直接读缓存就好。
高并发:操作缓存能承受的请求是远远大于访问数据库的,redis单机承载并发量是mysql 单机的几十倍。
三:读线程和写线程流程
读线程在查询数据的过程是这样的:
(1)查询缓存,如果缓存中有值,则直接返回
(2)查询数据库
(3)把数据库的查询结果更新到缓存中
写线程:是先删除缓存在更新数据库,还是先更新数据库在删除缓存
四:什么情况下会出现数据库和缓存不一致的问题?
- 在非并发的场景中:
因为缓存的操作和数据库的操作是存在一定的时间差的,而且这两个操作是没办法保证原子性的,有可能一个操作成功,一个操作失败。所以,这必然会存在不一致的情况。 - 在并发的场景中:
(1)如果两个线程,同时进行先写数据库,后更新缓存的操作,就可能会出现不一致
(2)如果两个线程,同时进行先更新缓存,后写数据库的操作,也可能会出现不一致
(3)读写并发,假如一个读线程,在读缓存的时候没查到值,他就会去数据库中查询,但是如果查询到结果之后,更新缓存之前,数据库被更新了,但是这个读线程是完全不知道的,那么缓存会重新用一个”旧值”覆盖掉。
五:如何解决Redis和数据库的一致性问题?
- 优先考虑删除缓存而不是更新缓存,我们放到缓存中的数据,可能是一个大的JSON串,更新缓存需要从缓存中取出数据,把他进行反序列化之后,把他修改掉,然后再序列化,最后再更新到缓存中。更新缓存相比较直接删除缓存复杂。如果是删除缓存的话,在写写并发的情况下,缓存中的数据都是要被清除,所以就不会出现数据不一致的问题。
- 先写数据库,后删除缓存,如果第二步失败了,会导致数据库中的数据已经更新,但是缓存还是旧数据,导致数据不一致。
- 先删除缓存后写数据库,那么第二步的失败是可以接受的,不会有脏数据,只需要重试就好了。但是先删除缓存后写数据库的这种方式,会无形中放大”读写并发"导致的数据不一致的问题。
最终解决办法:建议考虑延迟双删的策略,就是说在先删除缓存,再更新数据库,然后过个几秒再删一把缓存,避免因为并发出现脏数据。
六:为什么需要延迟双删,两次删除的原因是什么?
所谓延迟双删,其实是:1、先删除缓存 2、更新数据库 3、删除缓存
第一次删除缓存的原因:为了避免两个操作无法作为一个原子操作而导致的不一致问题,我们选择先删除缓存,再更新数据库。
第二次删除缓存的原因:第一步先把缓存给清了,缓存中的数据被读线程写进去脏数据,那么就需要写线程第二次删除了
七:删除缓存相比更新缓存的缺点?
删除缓存后,下一次查询会无法命中缓存,需要查询一下数据库。在某种程度上可能会导致缓存击穿,也就是刚好缓存被删除之后,同一个Key有大量的请求过来,大量请求访问到数据库。但是,通过加锁的方式是可以解决缓存击穿的问题。