update 更新缓存 mysql_先更新缓存还是先更新数据库

本文探讨了在更新数据库时如何同步缓存,分析了先更新缓存再更新数据库和先更新数据库再更新缓存两种策略的并发问题,以及异常情况的处理。先更新数据库再删除缓存的方法能更好地保证数据一致性,而先更新缓存可能导致数据不一致。
摘要由CSDN通过智能技术生成

一、提前阅读

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

1、考虑并发操作:线程A写,线程B读

dfb681afd11d335ee49ddaad1193b7f6.png

1、线程A发起一个写操作,第一步delete cache

2、此时线程B发起一个读操作,cache miss

3、线程B继续读数据库,读出来一个老数据

4、然后老数据入cache

5、线程A写入了最新的数据

这样以后每次从缓存中读到的都是老数据,造成数据不一致。

既然这种情况下先删除缓存会有数据不一致的情况,那我们来试试第一步不删除缓存而是直接更新缓存试试看。

2、考虑并发操作:线程A写,线程B写

a93ce52d62dc19ea3fa2e7f304b13472.png

1、线程A发起一个写操作,第一步set cache

2、线程B发起一个写操作,第一步set cache

3、线程B写入数据到数据库

4、线程A写入数据到数据库

这样以后每次从缓存中读到的都是线程B设置的数据,但数据库中存储的是线程A写入的数据,导致数据不一致。

3、小结

可看到先操作缓存不论是先删除缓存还是先更新缓存都会发生数据不一致的情况,所以不推荐这两种做法。

从理论上说,只要我们设置了缓存的过期时间,我们就能保证缓存和数据库的数据最终是一致的。因为只要缓存数据过期了,就会被删除。随后读的时候,因为缓存里没有,就得去查数据库的数据,然后将查出来的数据写入到缓存中。除了设置过期时间,我们还需要做更多的措施来尽量避免数据库与缓存处于不一致的情况发生。但是设置过期时间是基本操作,只要数据不是静态数据,就应该给缓存中的此类数据设置过期时间,它并不是解决“先更新缓存,再更新数据库”造成数据不一致问题的方法。

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

1、考虑并发操作:线程A写,线程B读

2bb945940f88826db106c86ffa58f067.png

1、线程A发起一个写操作,第一步写入数据到数据库

2、线程A第二步delete cache

3、线程B发起一个读操作,cache miss

4、线程B从数据库获取最新数据

5、线程B同时set cache

一个是读操作,一个是写操作的并发,首先没有了文章开始删除cache数据的操作了,而是先更新了数据库中的数据,此时缓存依然有效,所以此时读操作查到的是没有更新的旧数据,但是更新操作马上让缓存失效了,后续的查询操作再把数据从数据库中查出来。而不会像文章开头的那个逻辑产生的问题,即后续的查询操作一直都在读旧的数据。

特殊情况:

在高并发的场景下,可能会出现数据库与缓存数据不一致的的情况,考虑下面情形:

1、线程A发起一个写操作,还未操作数据库

2、缓存刚好失效

3、线程B查询数据库,得一个旧值

4、线程A将新值写入数据库

5、线程A删除缓存

6、线程B将查到的旧值写入缓存

但是这个条件需要发生在读缓存时缓存失效,而且并发着有一个写操作。而实际上数据库的写操作会比读操作慢得多,而且还要锁表,而读操作必须在写操作前进入数据库操作,而又要晚于写操作更新缓存,所有的这些条件都具备的概率其实并不大。

2、考虑并发操作:线程A写,线程B写,线程C读

c8ea8f8ac32de690c58194b1832ee701.png

1、线程A发起一个写操作,第一步写入数据到数据库

2、线程B发起一个写操作,第一步写入数据到数据库

3、线程B第二步delete cache

4、线程C发起一个读操作,cache miss

5、线程C从数据库获取最新数据

6、线程C同时set cache

7、线程A第二步delete cache

该情况下由于线程A、B最初都把数据写入了数据库,接着都有delete cache,此时如果有线程C来读数据,你会发现不管线程C的动作做任意顺序穿插在A、B动作之间,最后查询数据最差也就是在线程A、B删除cache之前获取到了旧数据,其余都会获取到新数据,并不会影响后来的请求获取到新数据。

为什么最后是把缓存的数据删掉,而不是把更新的数据写到缓存里。这么做引发的问题是,如果A、B两个线程同时做数据更新,A先更新了数据库,B后更新数据库,则此时数据库里存的是B的数据。而更新缓存的时候,是B先更新了缓存,而A后更新了缓存,则缓存里是A的数据。这样缓存和数据库的数据会发生不一致。

3、小结

先操作数据库再删除缓存能有让人可接受的结果,所以最推荐这种做法。

先操作缓存再更新数据库可能造成数据不一致的场景,不推荐这种做法。

四、异常情况

上面的讨论与对比都是在更新缓存和更新数据库这两步操作都成功的情况下叙述的。当然系统正常运行时的操作基本上都是成功的,那么如果两步操作有其中一步操作失败了呢?(以先操作数据库再操作缓存举例)

第一步失败:这种情况很简单,不会影响第二步操作,也不会影响数据一致性,直接抛异常出去就好了。

第二步失败:

将需要删除的缓存key发送到消息队列中

另起终端消费队列消息,获得需要删除的缓存key

设置重试删除操作,超过最大重试次数(比如5次)后将消息转入死信队列并报警给运维人员

五、参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值