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中间件

相关推荐
Li zlun9 分钟前
MySQL 性能监控与安全管理完全指南
数据库·mysql·安全
养生技术人1 小时前
Oracle OCP认证考试题目详解082系列第48题
运维·数据库·sql·oracle·database·开闭原则·ocp
海阳宜家电脑1 小时前
Lazarus使用TSQLQuery更新的一点技巧
数据库·lazarus·tsqlquery
沐浴露z1 小时前
分布式场景下防止【缓存击穿】的不同方案
redis·分布式·缓存·redission
丨我是张先生丨2 小时前
SQLSERVER 查找存储过程中某个变量
数据库
感谢地心引力2 小时前
【Python】基于 PyQt6 和 Conda 的 PyInstaller 打包工具
数据库·python·conda·pyqt·pyinstaller
韩立学长4 小时前
【开题答辩实录分享】以《走失人口系统档案的设计与实现》为例进行答辩实录分享
mysql·mybatis·springboot
lypzcgf4 小时前
Coze源码分析-资源库-编辑数据库-后端源码-数据存储层
数据库·coze·coze源码分析·智能体平台·ai应用平台
jackaroo20204 小时前
后端_Redis 分布式锁实现指南
数据库·redis·分布式
liuy96154 小时前
迷你论坛项目
数据库