如何保证缓存与数据库的一致性?


常见的缓存更新策略

  • 先更新缓存,再更新数据库
  • 先更新数据库,再更新缓存
  • 先删除缓存,再更新数据库
  • 先更新数据库,再删除缓存
  • 延时双删-更新数据库前后均删除缓存

如果系统不存在并发情况,这些策略都没问题,但是一旦协同并发上来后,这些策略都有问题,具体采用那些策略,需要根据具体的业务分析

先更新缓存,再更新数据库

这种策略一般不会使用,比如我们想象一种场景,我们先更新缓存,然后更新数据库,但是某些原因更新数据库失败了,那么肯定就会导致数据不一致。而且这个不一致,还会导致这次更新直接丢失了
因为大多数系统中,缓存是不会再写入数据库的,等到缓存失效,这次更新就彻底丢失了
在这里插入图片描述

先更新数据库,再更新缓存

这种缓存更新策略也被称为双写,会将脏数据更新到缓存中,想象一种场景,

  • 线程1更新数据库,数据库为1,但没来的及更新缓存
  • 线程2也进来更新数据库,数据库为2
  • 线程2速度比较快,马上更新了缓存,缓存为2
  • 线程1更新缓存。缓存为1

就导致数据库中的数据为线程2更新的,而缓存中的数据为线程1更新的,肯定不一致。

在这里插入图片描述

先删除缓存,再更新数据库

这种策略会导致请求的数据和实际数据库的数据不一致,如图,如果线程2再删除缓存和更新缓存操作之间发生了查询请求,那么请求到的数据就是旧数据,放入缓存的数据也为旧数据

  • 线程1要更新数据库,就会先删除缓存
  • 线程2要查询数据,发现没有缓存
  • 则线程2去查询数据库,此时得到的数据为1
  • 线程2查询数据后,将数据写入缓存,缓存中数据为1
  • 线程1更新数据库为2
  • 缓存与数据库数据不一致
    在这里插入图片描述
    如果不给缓存设置过期时间,那么缓存中的数据会一直都有脏数据

先更新数据库,再删除缓存

这个策略是目前用的比较多的,但是在特定情况下还是会有一些问题,模拟场景

  • 缓存刚好到过期时间
  • 线程1查询数据库为1
  • 线程2更新数据库为2
  • 线程2删除缓存
  • 线程1更新缓存为1

在这里插入图片描述

  • 不过好在这种场景需要更新数据库的时间远远小于查询数据库的时间,
  • 但实际上,查询数据库的操作远远快于写操作
  • 所以这次情况发生的概率相对来说比较少

延时双删-更新数据库前后均删除缓存

这种策略是比较推荐的策略,主要流程是

  • 更新数据库前,删除缓存
  • 更新数据库
  • 延时一定的时间,再删除缓存

这种策略可以确保读请求结束,写请求可以删除读请求造成的脏数据


Author: stream
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source stream !
  TOC