首先关于两者数据的一致性包含有两种情况:

 (1)缓存中有数据时,那数据库中的数据要和缓存中的数据相同;

 (2)缓存中没有数据时,数据库中的数据必须是最新的。

如果不符合以上两种情况,就属于缓存和数据库数据不一致的问题。

缓存不同的读写模式,所对应的不一致问题也会有所差异,缓存的读写模式主要有两种,读写缓存和只读缓存。

1.对于读写缓存来讲,需要关注缓存数据写完以后,对于数据库的写会策略,主要分为两种:

 (1)同步直写,写缓存的时候,也同步写数据库,这样数据一致,改策略适用于需要读写缓存和数据库数据一致的场景,但使用这种策略需要注意,缓存和数据库中的数据需要同时更新,所以需要在更新中使用事务机制,保证缓存和数据库的更新具有原子性,要么同时更新成功,要么都更新失败并返回错误信息,进行重试。

 (2)异步写回,写缓存时不写回数据库,等缓存中数据要被淘汰时,再写回数据库,但如果写完缓存,还未更新数据库时缓存出现故障,那要数据库中就没有最新的数据了,该种策略适用于对数据一致性要求不是那么高的场景,如电商商品的非关键属性和短视频的创建和修改时间等,可以使用该策略。

2.只读缓存的数据变更主要分为,增加新数据和删改已有的数据:

 (1)新增数据,对于新增数据,只需要直接添加到数据库中即可,不需要对缓存做什么操作。这样数据库中是最新的数据,缓存中没有新增数据,对应前面的数据一致性的第二种情况,也是数据一致的。

 (2)删改数据,如果发生删改数据,既要删改数据库中的数据,还要让缓存中的数据无效,同时还需要保证两个操作的原子性,要么都执行成功,要么都执行失败,不然都会导致数据不一致的情况发生,

    a.先更新数据库,后删缓存。可能发生缓存删除失败,下次查询命中缓存,但读取到的是旧值

    b.先删除缓存,后更新数据库。可能发生数据库更新失败,下次查询时缓存中没有,从数据库中获取的是未更新的旧值。

    解决该种场景下的数据不一致问题,可以采用重试方法,考虑使用如Kafka消息队列,把要删改的数据放入到Kafka中,只有缓存和数据库同时操作成功时,才将其从消息队列中删除,否则重新读取并操作,重试次数超过一定限制时返回相应的错误。

    对应上面两种删除的场景和顺序,由于执行先后的时间差的缘故,也有可能导致不同的数据不一致的问题出现,但也可以有针对性的不同解决策略:

      1. 针对先删除缓存再更新数据库的场景,可能会出现线程A先删除了缓存但并没来得急更新数据库,这时线程B来读取,缓存中没有,将从数据库中读取,a.但读到的是旧值,b.同时还会导致将该旧值同步到缓存中。

        解决方法:可以再线程A更新完数据库时,sleep一小段时间(这个时间要大于线程B从数据库中读取数据并更新缓存的时间),然后线程A再删除缓存,之后再有其他线程来读取时,发现缓存缺失,则会从数据库中读取最新的值,并更新至缓存中

             这个方法就叫做延迟双删。

      2. 针对先更新数据库,后删除缓存这种场景,可能存在线程A先更新了数据库还没来及删除缓存的时候,线程B来读取并命中缓存,但是读到了旧值

        解决方法:也可以使用延迟双删

    总结下来:(1)对于更新数据库或者删除缓存可能失败导致的不一致,可以采用重试的方式解决;

         (2)对于删除缓存和更新数据库过程中,由于存在其他并发线程读取而导致的不一致问题,可以采用延迟双删的方法来解决。

    建议使用先更新数据库,再删除缓存的顺序,原因如下:

        (1)先删缓存,再更新数据库,可能由于缓存的缺失而访问数据库,进而给数据库带来压力

        (2)如果业务应用中读取数据库和写缓存的时间不好估算,那么,延迟双删中的等待时间就不好设置。

PS:如果业务层要求必须读取一致性的数据,可以在更新数据库的同时,现在redis缓存暂存客户端并发读请求,等数据库更新完,缓存删除完,再来读取,保证数据一致性。

参考《Redis核心技术与实战》蒋德钧

Redis缓存中的数据和数据库不一致的更多相关文章

  1. springboot中如何向redis缓存中存入数据

    package com.hope;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jack ...

  2. [转]在nodejs使用Redis缓存和查询数据及Session持久化(Express)

    本文转自:https://blog.csdn.net/wellway/article/details/76176760 在之前的这篇文章 在ExpressJS(NodeJS)中设置二级域名跨域共享Co ...

  3. 基于Python项目的Redis缓存消耗内存数据简单分析(附详细操作步骤)

    目录 1 准备工作 2 具体实施   1 准备工作 什么是Redis? Redis:一个高性能的key-value数据库.支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使 ...

  4. EF封装类 增加版,增加从缓存中查找数据方法,供参考!

    EF封装类 增加版,增加从缓存中查找数据方法,供参考! 这个类是抽象类,我这里增加了需要子类验证的方法ValidateEntity,方便扩展,若想直接使用该类,可以将该类更改成静态类,里面所有的方法都 ...

  5. 在nodejs使用Redis缓存和查询数据及Session持久化(Express)

    在nodejs使用Redis缓存和查询数据及Session持久化(Express) https://segmentfault.com/a/1190000002488971

  6. 简单实现Redis缓存中的排序功能

    1.在实现缓存排序功能之前,必须先明白这一功能的合理性.不妨思考一下,既然可以在数据库中排序,为什么还要把排序功能放在缓存中实现呢?这里简单总结了两个原因:首先,排序会增加数据库的负载,难以支撑高并发 ...

  7. redis(四)--简单实现Redis缓存中的排序功能

    在实现缓存排序功能之前,必须先明白这一功能的合理性.不妨思考一下,既然可以在数据库中排序,为什么还要把排序功能放在缓存中实现呢?这里简单总结了两个原因:首先,排序会增加数据库的负载,难以支撑高并发的应 ...

  8. Redis缓存中的常见问题

    缓存穿透:是指查询一个Redis和数据库中都不存在的数据. 问题:查询一个Redis和数据库中都不存在的数据,大量请求去访问数据库,导致数据库宕机. 解决办法: 1.根据id查询,如果id是自增的,将 ...

  9. 获取apache ignite缓存中的数据行数少于实际行数

    我将ignite项目打包放到linux下,在linux下获取window中存放在oracle数据库中的数据,linux服务器作为ignite的服务端节点,我在本地启动tomact,作为ignite客户 ...

  10. Java -> 把Excel表格中的数据写入数据库与从数据库中读出到本地 (未完善)

    写入:没有关闭流,容错并不完善. private void insertFile(HttpServletRequest request, HttpServletResponse response) t ...

随机推荐

  1. Shapefile导入MySQL

    1. 概述 Shapefile是常用的空间数据文件格式,MySQL是常用的关系型数据库 MySQL遵从OpenGIS联盟(OGC)的规范,MySQL实施了空间扩展,更详细的信息可以参考: MySQL ...

  2. YML

    一.YML语法 1.约定 k: v 表示键值对关系,冒号后面必须有一个空格 使用空格的缩进表示层级关系,空格数目不重要,只要是左对齐的一列数据,都是同一个层级的 大小写敏感 缩进时不允许使用Tab键, ...

  3. sql_server数据库

    问题:如何在SQL SERVER中合并时间和日期? 解决方法1:使用+合并时间日期让我们运行以下命令:SELECT CAST(字段名 AS DATETIME) + CAST(字段名 AS DATETI ...

  4. Django views.py 增,删,改

    from django import forms from django.shortcuts import render, redirect from app01 import models # Cr ...

  5. RDD编程练习

    一.filter,map,flatmap练习: 1.读文本文件生成RDD lines 2.将一行一行的文本分割成单词 words 3.全部转换为小写 4.去掉长度小于3的单词 5.去掉停用词 6.练习 ...

  6. Cookie之记录用户上次访问时间

    Cookie之记录用户访问时间 需求: 需求: 1:用户访问服务器(Servlet),判断用户是否是第一次访问,如果是第一次访问,则在页面响应内容为:"您好,欢迎您首次访问"; 2 ...

  7. JavaSE——复杂对象数组练习

    定义一个长度为3的数组,数组存储1~3名学生对象作为初始数据,学生对象的学号,姓名各不相同. 学生的属性:学号,姓名,年龄. 要求1:再次添加一个学生对象,并在添加的时候进行学号的唯一性判断. 要求2 ...

  8. PHP_工厂模式

    实例化类,先需要引入类文件,但是有时候我们并不知道可能要用到那些类,如果将所有类文件全部引入,会造成资源浪费,这时候可以采用工厂模式,专门用于 自动加载.实例化 类. 实例代码: 注:案例中假设有一个 ...

  9. CompletableFuture的thenCompose使用具体说明

    1.thenCompose 如果你还没有了解CompletableFuture或者希望再次熟悉一下,可以参考 CompletableFuture使用方法详细说明 1.1. thenCompose的特点 ...

  10. 常用得cron表达式

    0 10 0 1 * ? //每月1号的0:10:00执行 0 01 00 28-31 * ? #月底最后一天早上凌晨1点执行 异常: 查询是否有特殊字符: cat -A ***.sh 解决方法: 1 ...