Redis 和 Mysql 数据库数据如何保持一致性

一、操作

我们在实际项目中经常会使用到Redis缓存用来缓解数据库压力,但是当更新数据库时,如何保证缓存及数据库一致性,一般我们采用延时双删策略。

目前系统中常用的做法是一个查询接口,先查询Redis,如果不存在则查询数据库,并将结果放入到Redis中。

为什么是删除缓存,而不是更新缓存呢?主要是如果缓存的内容是带有树型结构或者List,Map,那么更新其中一个内容相对较慢。

本文所讲操作,均是按照如果缓存不存在,查询数据库后,再放入Redis。

二、 常见更新策略

  • 1 先删缓存,再更新数据库

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

  • 3 普通双删

  • 4 延迟双删

三、图解

1 、先删缓存,再更新数据库

线程A删除缓存数据,此时还没更新数据库

线程B查询缓存没有数据,查询数据库还是旧数据,放入缓存

线程C及其他线程使用旧缓存数据,缓存和数据库不一致

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

线程A更新数据库,此时还没有删除缓存

线程B及其他线程此时使用的还是旧缓存数据,和数据库内容不一致

3 、普通双删

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

线程B查询缓存没有数据,在线程A更新数据库之前,查询到旧数据,此时系统时间片切换到线程A执行删除缓存,之后又轮到线程B放入缓存旧数据

线程C针对于线程A,查询缓存没有数据,查询到旧数据,放入缓存旧数据

都不能满足缓存和数据一致性。

4、延迟双删

线程A先删除缓存,之后更新数据库

线程B和线程C发现缓存没数据,查询数据库。线程B查询到的是旧数据,线程C查询到的是新数据。之后纷纷放入缓存

线程A延时3-5秒(时间一般要大于SQL执行时间+线程切换执行时间100ms足够),再将缓存删除。之后其他线程再查询缓存,发现没数据,再次查询数据库及放入缓存都是新数据

极端情况就是线程D,所以延时双删还是不一定能保证缓存及数据一致。

四、总结:

1、加锁

在发现缓存没有数据后,在执行查询数据库前,对该Key进行加锁,查询数据库并放入缓存后再解锁,这样可以避免缓存击穿问题,当某个redis数据不存在时,大量线程并发查询数据库。

在需要执行双删前,对该Key进行加锁,之后执行删除缓存,更新数据库,放入新数据到缓存,在解锁。保证缓存和数据一致性。

加锁的Key都需要设置过期时间,避免因为宕机造成死锁。

2、使用Canal 分布式数据库同步工具,结合mq中间件

相关推荐
2301_7816686121 分钟前
Redis 面试
java·redis·面试
吐泡泡_27 分钟前
Redis(缓存)
redis
Java水解35 分钟前
【MySQL】数据库基础
后端·mysql
沃夫上校38 分钟前
MySQL 中文拼音排序问题
java·mysql
要一起看日出39 分钟前
MVCC-多版本并发控制
数据库·mysql·mvcc
Hx__39 分钟前
MySQL InnoDB 的 MVCC 机制
数据库·mysql
速易达网络40 分钟前
ASP.NET MVC 连接 MySQL 数据库查询示例
数据库·asp.net·mvc
无名客01 小时前
redis分布式锁为什么采用Lua脚本实现。而不是事务
redis·分布式·lua·事务
玉衡子1 小时前
MySQL基础架构全面解析
数据库·后端
梦中的天之酒壶1 小时前
Redis Stack扩展功能
数据库·redis·bootstrap