如何保证数据库和缓存数据一致

部分场景下,对于数据库中需要频繁访问的热点数据,会保存一份拷贝在 redis 缓存,提高查询效率,具体流程如下:

  • 对于查询操作,首先从缓存中查询,查到直接返回,否则从数据库查询,将查询结果保存在缓存中,然后返回
  • 对于更新操作,先修改数据库,再删除缓存

上述流程的执行就需要保证数据库和缓存数据一致。这里每次更新操作后删除缓存的原因在于:

  1. 部分场景下缓存中的数据是数据库数据加工后的结果,可能需要联合其它数据一起计算,因此暂时删除掉
  2. 使用缓存的主要原因在于提高查询效率,数据库中的数据不一定都会查到,因此先删掉,具体用到时再保存

无论是先更新数据库还是先删除缓存,都可能造成脏读问题:

  • 先操作数据库:在修改完数据库,清空缓存期间,读取到的数据都是脏数据
  • 先清空缓存:假如在修改数据库期间读取数据并写缓存,后续读取到的都是脏数据

虽然都可能造成脏读,但总的来说先操作数据相对更加安全,


常见数据不一致的场景:

1、先更新数据库,再删除缓存:数据库更新成功,缓存删除失败,此时数据库是新数据,缓存为老数据

解决思路:调整顺序,先删除缓存,再更新数据库,这样删除缓存失败就不会更新数据库、假如删除缓存成功,更新数据库失败,缓存中没有数据,下次查询走数据库,数据仍然一致

2、复杂并发场景:收到更新数据请求,先清空了缓存,后执行数据库修改,在执行数据库操作期间,另一个请求读取数据,先检查缓存为空,读取到还未修改的老数据,返回并保存在缓存中,随后第一通请求完成数据库更新,数据库和缓存数据不一致。

解决思路:使用双删法,更新数据库数据前后都删除一次缓存,简单好实现。

还有一种比较复杂的思路:更新数据时,根据数据的唯一标识,将操作分配到一个队列中,读取数据时,如果缓存中没有,将读取操作和更新缓存也放入队列,队列中的操作串行执行。使用该方案需要注意很多问题:

  • 读请求长时间阻塞:修改操作很多时,读请求在队列中长时间不能执行。此时可以设置最大过期时间,超过该时间直接走数据库
  • 读请求并发量很大:如果大量的读请求阻塞在服务上,服务能否撑住,根据具体场景判断是否需要扩容
  • 多服务实例部署的请求路由:对于同一类商品的操作,必须保证打到同一个队列上

还有一种很极端的处理办法:串行化,增加同步机制,也就是修改操作和删除缓存操作串行执行,期间不允许其它线程并发访问,这种处理方式虽然能解决一致性问题,但代价太大,非常影响性能。

一般情况下,使用数据库配合缓存是允许一部分脏读情况发生的,如果真的强依赖一致性,建议只使用数据库,确保数据安全。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值