首页 > 数据库 >如何保证MySQL和Redis数据一致性?

如何保证MySQL和Redis数据一致性?

时间:2024-04-01 13:58:43浏览次数:22  
标签:缓存 Redis 更新 查询 MySQL 一致性 数据

背景


在高并发的业务场景中,因为MySQL数据库是操作磁盘效率比较低,因此大多数情况下数据库都是高并发系统的瓶颈。因为Redis操作数据是在内存中进行,所以就需要使用Redis做一个缓存。让请求先访问到Redis,而不是直接访问MySQL数据库。效果图如下

Untitled

查询数据


上面的业务场景,就是一个典型的MySQL存储数据和Redis缓存数据的业务场景。下面来看看一般的查询流程,如下图:

Untitled

上面的查询流程如下:

  1. 用户请求系统,系统先查询Redis中是否有数据?
  2. 如果Redis中有数据,则直接将缓存中的数据响应给用户。
  3. 如果Redis中没有数据,则取查询MySQL数据库中是否有数据?
  4. 如果MySQL中有数据,则先将数据更新到Redis中,再将数据响应给用户。
  5. 如果MySQL中没有数据,则响应空数据给用户,请求结束。

上面的查询流程很简单,通过先查Redis缓存,避免大量请求访问MySQL数据库,从而大大提高系统响应效率。而且如果Redis中没有而MySQL中有,当从MySQL拿到数据以后,先将数据更新到Redis缓存中,这样下次请求同一份数据的时候就能从Redis中获取了。

更新数据


上面的查询流程是没什么问题,可是数据很有可能会更新。那么更新的时候怎么操作才能保证Redis和MySQL中的数据都更新成功并且一致呢?

下面看看一种常用的解决方案(双删缓存):

Untitled

第一个问题:为什么是删除Redis缓存数据而不是更新数据?

假设我们缓存的数据是要做一个很复杂的计算,而且还不一定能用到。那如果你更新MySQL数据之后去更新Redis缓存不是就很耗时了,而且有可能做无用功。

第二个问题:为什么是先删除Redis缓存数据而不是先更新数据库呢?

我们不妨假设先更新MySQL中的数据,然后再删除缓存。如果更新完MySQL但是删除Redis失败了(别问为什么会失败?系统故障行不行,全球断电行不行?),那下次查询请求过来,因为Redis中有缓存数据,所以直接返回Redis缓存的旧数据了,是不是就出问题了?

那我们再看看,如果先删除Redis缓存,再更新MySQL。如果删除完Redis成功,但是更新MySQL失败。下次查询的时候,查询到Redis缓存发现没有,再去查MySQL,然后更新到Redis,虽然MySQL更新失败了,但是Redis中的数据和MySQL是一致的。

第三个问题:为什么更新完MySQL后还要再删一次Redis缓存呢?

假设我们第一次删完Redis结束,正在更新MySQL但是还没更新成功的时候,这时候有另外一个请求来查询数据。第二个请求查询Redis没有,然后查询MySQL这时候因为MySQL还没更新完,所以查询到的还是旧数据,同时把旧数据更新到Redis中了,等下一个请求再来查询的时候发现Redis有数据,就直接返回旧数据了。

因此更新完MySQL后需要再次删除Redis缓存。这样即使更新数据中间有其他个请求把旧数据更新到Redis中了,因为再次删了Redis缓存中的旧数据,依然能够避免其他请求获取到旧数据。

我们认为数据是否更新成功是以MySQL中的数据为准,因此MySQL还没更新完成前或者更新失败,获取到旧数据不算是问题。所以我们只要保证Redis和MySQL中的数据一致就行。

标签:缓存,Redis,更新,查询,MySQL,一致性,数据
From: https://www.cnblogs.com/lvlaotou/p/18108249

相关文章

  • mysql语法和函数使用
    group_concat()参考连接:https://www.jb51.net/article/87328.htm手册上说明:该函数返回带有来自一个组的连接的非NULL值的字符串结果。比较抽象,难以理解。通俗点理解,其实是这样的:group_concat()会计算哪些行属于同一组,将属于同一组的列显示出来。要返回哪些列,由函数参数(就是字......
  • [转帖]mysql 获取昨天日期、今天日期、明天日期以及前一个小时和后一个小时的时间,mysq
    https://www.cnblogs.com/jpfss/p/8759284.html1、当前日期selectDATE_SUB(curdate(),INTERVAL0DAY);2、明天日期selectDATE_SUB(curdate(),INTERVAL-1DAY);3、昨天日期selectDATE_SUB(curdate(),INTERVAL1DAY);4、前一个小时时间selectdate_sub(now(),in......
  • 基于SSM+Jsp+Mysql的美食推荐管理系统
    开发语言:Java框架:ssm技术:JSPJDK版本:JDK1.8服务器:tomcat7数据库:mysql5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:Maven3.3.9系统展示前台首页功能用户注册界面用户登录界面热门美食界面美食店铺界面用户管理界面美食分类管理热......
  • 本地服务器连接远程服务器上的MySQL
    上周日,在做项目时,连接不上远程服务器,导致数据库不能正常使用,(因为忘记密码了)查阅了很多资料,最终算是解决了吧。写一下自己的感悟。注意,本文是远程数据库的连接,所以是在远程服务器上工作的。我用的远程服务器是Linux系统,MySQL是5.7版本一、进入mysql需要密码,所以,我们得先跳过输......
  • 预防 MySQL 死锁的策略
    1、按顺序访问数据:按照一定的顺序访问数据可以减少死锁的发生。例如,如果多个线程或事务需要更新多个表,可以按照相同的顺序来执行更新操作。这样可以避免循环等待和资源竞争。2、避免长时间持有锁:尽量缩短事务的执行时间,避免长时间持有锁。长时间持有锁会增加其他事务等待的......
  • C#中的缓存处理方案 (MemoryCache,Redis)
    缓存处理在C#和WPF日常开发中非常重要,可以提高应用程序的性能和响应速度。以下是关于缓存处理方案的知识点,以及可能会在面试中被问到的一些问题和答案:缓存处理方案的知识点:内存缓存:内存缓存是最常见的一种缓存处理方案,它将数据存储在应用程序的内存中,以提高数据的访问速......
  • C#中的消息中间件(RabbitMQ 和 Redis)
    消息中间件是一种用于在分布式系统中进行异步通信的技术,常用于解耦应用程序的不同组件、实现消息传递、提高系统的可伸缩性和可靠性等。以下是关于消息中间件的知识点以及可能会在面试中被问到的一些问题和答案:消息中间件的知识点:消息队列(MessageQueue):消息中间件通常基于消......
  • 【数据库】[MYSQL][面试题]常见数据库知识整理
    常见数据库:MySQL:是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。MySQL使用C和C++编写,并使用了多种编译器进行测试,保证了源代码的可移植性。支持多线程,充分利用CPU资源。提供多语言支持......
  • MySQL数据库报错:ERROR 1364 (HY000): Field ‘authentication_string‘ doesn‘t have
    在MySQL安装和配置的过程中,遇到错误可能会让人感到困惑,尤其是当错误信息不够清晰时。本文将详细探讨一个在MySQL安装过程中较少见但可能会遇到的错误,提供一个全面的解决方案指南。错误描述在MySQL安装过程中,可能会遇到以下错误信息:ERROR1364(HY000):Field'authentica......
  • Redis+lua脚本配合AOP限流
    限流Redis脚本限流脚本配合切面注解定义注解:@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceRateLimiter{/***限流key*/publicStringkey()defaultCacheConstants.RATE_LIMIT_KEY;/**......