首页 > 数据库 >解决Redis和数据库一致问题

解决Redis和数据库一致问题

时间:2024-02-24 19:11:34浏览次数:30  
标签:缓存 双删 删除 数据库 Redis 更新 一致

昨天面试了一家公司,简历上我写了用redis做缓存,当面试官问到,当有用户修改了信息,怎么做到缓存的信息和数据库一致呢,当时或许是紧张或许是真不知道,还是脑子短路了,就没回答出来。

面试完和我舍友提到的时候,慢慢就想起以前看到过类似的解决方法:那就是当用户的信息有更新的时候就进行缓存和数据库双写,然后在具体的操作中,考虑延迟双删策略:即

  • 删除缓存
  • 更新数据库
  • 再次删除缓存

 就是说先删除缓存,再更新数据库,过几秒后再删除一下缓存,这就避免了并发产生的的脏数据,在这其中延伸出几个思考:

1、为什么选择删除缓存呢?

缓存中的数据可能不只是简单的一个字符串类型,还有可能是其他json串的。如果需要对其进行修改的话则需要进行序列化之后,再解析出其中的字段,把其修改之后再序列化,最后再更新到缓存之中。由此可知更新缓存的动作相比于直接删除缓存更加的复杂,页容易出错。

2、先写数据库还是先删缓存?

先写数据库:

因为数据库和缓存的 操作是两个不同的操作,所以没办法做到原子性,所以就有可能一个操作成功另外一个操作失败。

把删除缓存放到第二步,如果失败了,会出现一个情况,那就是数据库的数据已经更新,但是缓存还是旧数据,导致数据不一致的问题。

先删缓存

如果是先删缓存后写数据库的话,那么第二步的失败还是可以接受的,以为这样不会有脏数据,没什么影响,只需要重试就好。

第二个好处就是:缓存删除的失败概率比较低,一般只有网络问题或者是缓存服务器宕机才出现,所以先删除缓存还是很有保障的。

先删缓存后写数据库这种方式,也会存在一个问题。我们先捋一下使用缓存后读线程的过程:

  • 查询缓存,如果缓存中有值,则直接返回
  • 查询数据库
  • 把数据库中的查询结果更新到缓存之后

所以对于一个读线程来说,虽然不会写数据库,但是会更新缓存,所以在并发情况下会存在数据不一致的情况。

也就是说,假如一个读线程,在读缓存的时候没查询值就是到数据库中查询。但是如果在查到结果之后,更新缓存之前,数据库被另一个线程进来更新了,但是前面那个读线程是完全不知道的,那么就是导致最终缓存会被更新成一个“旧值”覆盖掉了。

虽然发生的概率比较低,但是还是有很低的概率发生,因为读的操作是比写操作要耗时的。一旦这种情况发生,后果也是比较严重的,那就是缓存中的值一旦是错的,就会导致后续所有的从缓冲中查询到的结果都是错的,所以为了进一步解决这种问题,那就是过几秒钟之后再删除一次缓存,就是一开始提到的延迟双删。

3、有第二次删除,第一次还有意义吗?

如果没有第一次删除,只保留第二次删除那么这个流程就变成了:

  • 更新数据库
  • 更新缓存

这个方案一旦删除缓存失败了就会导致数据不一致的问题。

那如果延迟 双删的第二次删除不也一样有可能失败么?

的确,第二次删除也还是有失败的概率,但是比因为我们在延迟双删的方案中先做了一次删除,而延迟双删的第二次删除只为了 尝试解决  因为读写并发导致的不一致问题,或者说尽可能降低这种情况发生的概率。

如果没有第一次删除,只靠第二次删除,那么就不只是解决读写并发情况下不一致的问题了。即使没有并发,第二次只要删除失败,就会存在缓存不一致的问题,所以,第一次删除的目的就是降低不一致的发生概率。

 

总之,通过前后两次删除的设置,就可以降低不一致的概率了。

 

标签:缓存,双删,删除,数据库,Redis,更新,一致
From: https://www.cnblogs.com/ChenRicky/p/18031392

相关文章

  • Ubuntu22.04安装mysql8数据库
    1、去官网下载APT存储库文件2、到/usr/local目录下创建mysql目录并且用rz命令上传下载的文件若没有安装lrzsz自行安装。3、解压下载的文件)直接选择OK4、更新包信息5、安装设置初始密码选第二个选项6、登录数据库......
  • 远程连接Mysql数据库
    showdatabases;usemysql;showtablse;selectuser,hostfromuser;updateusersethost='%'whereuser='root';flushprivileges;......
  • js_将excel内容先存入数据库,再将数据显示到页面
    <%--将excel数据显示到页面--%><scripttype="text/javascript">//原创来自www.luofenming.com//首先监听input框的变动,选中一个新的文件会触发change事件document.querySelector("#testFile").addEventListener("change",function(){......
  • [数据库] 使用索引(2): mongoDB
    mongoDB的索引mongodb的索引和mysql基本类似,也是默认主键(相当于mongo中的_id字段)为索引,进行索引排序etc.索引分类单键索引将一个字段作为索引,默认_id,也可以将其他字段作为索引db.collection.createIndex({year:1})其中value为1则是正序,为-1则是倒序复合索引......
  • [数据库] 使用索引(1): MySQL
    索引indexing索引是用来提高查询效率的,会将数据按照被设为索引的字段进行排序,这样根据该字段查找的时候更快数据库在没有索引的情况下,默认进行全文搜索,这意味着所有数据都会被遍历到索引和数据文件一样存储在磁盘上,因此过多的索引会占用空间;索引和数据文件的关联......
  • SpringBoot + Redis 的配置及使用
    一、SpringBoot配置Redis1.1pom引入spring-boot-starter-data-redis包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></......
  • 数据库基础3 关系数据库与关系模型
    数据库系统的组成1.硬件平台2.软件3.人员(1)数据库管理员(DBA)(2)系统分析员、数据库设计人员(3)应用程序员(4)最终用户1.偶然用户2.简单用户3.复杂用户 关系数据库关系模型是从表(Table)的处理方式中抽象出来的在对传统表的操作上,进行数学化严格定义的基础上,......
  • 数据库基础2 数据模型
    数据模型数据模型是什么数据模型是对现实世界数据特征的抽象数据模型应该满足的要求数据模型分类1.现实→概念→逻辑→物理转换过程2.概念模型信息世界基本概念实体(Entity)属性码(键)实体型实体集 联系 ER图:实体-联系方法(待续)数据模型的组成要素1.数......
  • 数据库基础4 关系代数运算
    基本操作前提条件:并相容性是并、差、交等关系代数操作的前提参与运算的两个关系及其相关属性之间必须又一定的对应性、可比性或关联性两个关系的属性数量必须相同对于任意i,关系R的第i个属性必须与另一个关系的第i个属性的域相同(数据类型、取值范围)一、传统集合运算并......
  • 数据库基础5 关系演算
    “关系代数是基于集合的查询”“关系演算是基于逻辑的查询”他们共同构成了数据库结构化查询语言SQL的基础关系演算概述关系演算是以谓词演算为基础的 关系元组演算1.公式的递归构造sitar:比较运算(>、<、>=、<=、!=、==)只有这几条之内的,属于【公式】所有公式都是由......