数据库与缓存数据不一致的解决方法
- 先更新数据库,后更新缓存
并发更新数据库场景下,会将脏数据写到缓存,因为缓存的读写速度要远远快于数据库

数据库中为2,缓存中是1
用户说我充值100,但过了一会儿用户说我充200吧,100有点少了,数据库更新成了200,缓存也更新成了200,但第一次请求写入缓后,缓存为100,下次访问的时候,缓存命中的是100,数据不一致
- 先更新缓存,后更新数据库

- 先删除缓存,再更新数据库
缺点是可能会导致缓存击穿,删除缓存后,如果大量请求访问该数据,会导致请求直接打到数据库,造成数据库压力读到脏值,例如:
A请求进行更新,B请求进行查询
A删除缓存,B查询时发现缓存中没有数据,会去数据库中查询,得到旧值
B将旧值写入缓存
A将新值写入数据库
解决方案:延时双删
先删除缓存,再更新数据库,延迟1s后再次删除缓存,确保再读请求之后,写请求可以删除读请求造成的脏数据
延时操作,性能下降怎么办?将第二次删除改为异步,用另一个线程进行删除
第二次删除失败怎么办?同步重试,异步消息队列(失败后,人工处理等),过期时间兜底
- 先更新数据库,再删除缓存
优点:减少时间不一致的窗口
避免缓存击穿,即使缓存被删除,后续请求也会重新加载最新数据到缓存中
缺点:短暂不一致,更新数据库后,删除缓存前,读请求会读到缓存中的旧值
例如
A请求查询,B进行更新
A查询得到旧值
B将新值写入数据库
B删除缓存
A将旧值写入缓存
解决方案:
- 异步延时删除
- 加入重试机制
- 方案一:消息队列重试
-
- 更新数据库
- 缓存删除失败(出现问题)
- 将失败的key放入消息队列
- 其他线程监听消息队列,获得需要删除的key
- 重试删除操作,直到成功为止
- 缺点:需要修改业务的代码逻辑,复杂难维护
-
- 方案二:订阅binlog日志
-
- 更新数据库数据
- 订阅binlog日志(保存了数据库的变更记录),拿到具体要操作的数据
- 执行缓存删除
-
- 方案一:消息队列重试