千家信息网

Java中怎么保证缓存一致性

发表于:2025-11-11 作者:千家信息网编辑
千家信息网最后更新 2025年11月11日,这篇文章主要介绍"Java中怎么保证缓存一致性",在日常操作中,相信很多人在Java中怎么保证缓存一致性问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Java中怎么保证
千家信息网最后更新 2025年11月11日Java中怎么保证缓存一致性

这篇文章主要介绍"Java中怎么保证缓存一致性",在日常操作中,相信很多人在Java中怎么保证缓存一致性问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Java中怎么保证缓存一致性"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

方案一:更新缓存,更新数据库

这种方式可轻易排除,因为如果先更新缓存成功,但是数据库更新失败,则肯定会造成数据不一致。

方案二:更新数据库,更新缓存

这种缓存更新策略俗称双写,存在问题是:并发更新数据库场景下,会将脏数据刷到缓存

updateDB();updateRedis();

举例:如果在两个操作之间数据库和缓存又被后面请求修改,此时再去更新缓存已经是过期数据了。

方案三:删除缓存,更新数据库

存在问题:更新数据库之前,若有查询请求,会将脏数据刷到缓存

deleteRedis();updateDB();

举例:如果在两个操作之间发生了数据查询,那么会有旧数据放入缓存。

该方案会导致请求数据不一致

如果同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么会出现如下情形:

  • 请求A进行写操作,删除缓存

  • 请求B查询发现缓存不存在

  • 请求B去数据库查询得到旧值

  • 请求B将旧值写入缓存

  • 请求A将新值写入数据库

上述情况就会导致不一致的情形出现。而且,如果不采用给缓存设置过期时间策略,该数据永远都是脏数据。

方案四:更新数据库,删除缓存

存在问题:在更新数据库之前有查询请求,并且缓存失效了,会查询数据库,然后更新缓存。如果在查询数据库和更新缓存之间进行了数据库更新的操作,那么就会把脏数据刷到缓存

updateDB();deleteRedis();

举例:如果在查询数据库和放入缓存这两个操作中间发生了数据更新并且删除缓存,那么会有旧数据放入缓存。

假设有两个请求,一个请求A做查询操作,一个请求B做更新操作,那么会有如下情形产生

  • 缓存刚好失效

  • 请求A查询数据库,得一个旧值

  • 请求B将新值写入数据库

  • 请求B删除缓存

  • 请求A将查到的旧值写入缓存

如果发生上述情况,确实是会发生脏数据。但是发生上述情况有一个先天性条件,就是写数据库操作比读数据库操作耗时更短

不过数据库的读操作的速度远快于写操作的

因此这一情形很难出现。

方案对比

方案1和方案2的共同缺点:

并发更新数据库场景下,会将脏数据刷到缓存,但一般并发写的场景概率都相对小一些;

线程安全角度,会产生脏数据,比如:

  • 线程A更新了数据库

  • 线程B更新了数据库

  • 线程B更新了缓存

  • 线程A更新了缓存

方案3和方案4的共同缺点:

不管采用哪种顺序,2种方式都是存在一些问题的:

  • 主从延时问题:不管是先删除还是后删除,数据库主从延时可能导致脏数据的产生。

  • 缓存删除失败:如果缓存删除失败,则都会产生脏数据。

问题解决思路:延迟双删,添加重试机制,下面介绍!

更新缓存还是删除缓存?

  • 1.更新缓存缓存需要有一定的维护成本,而且会存在并发更新的问题

  • 2.写多读少的情况下,读请求还没有来,缓存以及被更新很多次,没有起到缓存的作用

  • 3.放入缓存的值可能是经过复杂计算的,如果每次更新,都计算写入缓存的值,浪费性能的

删除缓存优点:简单、成本低,容易开发;缺点:会造成一次cache miss

如果更新缓存开销较小并且读多写少,基本不会有写并发的时候可以才用更新缓存,否则通用做法还是删除缓存。

总结

方案问题问题出现概率推荐程度
更新缓存 -> 更新数据库为了保证数据准确性,数据必须以数据库更新结果为准,所以该方案绝不可行不推荐
更新数据库 -> 更新缓存并发更新数据库场景下,会将脏数据刷到缓存并发写场景,概率一般写请求较多时会出现不一致问题,不推荐使用。
删除缓存 -> 更新数据库更新数据库之前,若有查询请求,会将脏数据刷到缓存并发读场景,概率较大读请求较多时会出现不一致问题,不推荐使用
更新数据库 -> 删除缓存在更新数据库之前有查询请求,并且缓存失效了,会查询数据库,然后更新缓存。如果在查询数据库和更新缓存之间进行了数据库更新的操作,那么就会把脏数据刷到缓存并发读场景&读操作慢于写操作,概率最小读操作比写操作更慢的情况较少,相比于其他方式出错的概率小一些。勉强推荐。

推荐方案

延迟双删

采用更新前后双删除缓存策略

public void write(String key,Object data){  redis.del(key);     db.update(data);     Thread.sleep(1000);     redis.del(key); }
  • 先淘汰缓存

  • 再写数据库

  • 休眠1秒,再次淘汰缓存

大家应该评估自己的项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上即可。

这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

问题及解法:

1、同步删除,吞吐量降低如何处理

将第二次删除作为异步的,提交一个延迟的执行任务

2、解决删除失败的方式:

添加重试机制,例如:将删除失败的key,写入消息队列;但对业务耦合有些严重;

延时工具可以选择:

最普通的阻塞Thread.currentThread().sleep(1000);

Jdk调度线程池,quartz定时任务,利用jdk自带的delayQueue,netty的HashWheelTimer,Rabbitmq的延时队列,等等

实际场景

我们有个商品中心的场景,是读多写少的服务,并且写数据会发送MQ通知下游拿数据,这样就需要严格保证缓存和数据库的一致性,需要提供高可靠的系统服务能力。

写缓存策略

  • 缓存key设置失效时间

  • 先DB操作,再缓存失效

  • 写操作都标记key(美团中间件)强制走主库

  • 接入美团中间件监听binlog(美团中间件)变化的数据在进行兜底,再删除缓存

读缓存策略

  • 先判断是否走主库

  • 如果走主库,则使用标记(美团中间件)查主库

  • 如果不是,则查看缓存中是否有数据

  • 缓存中有数据,则使用缓存数据作为结果

  • 如果没有,则查DB数据,再写数据到缓存

注意

关于缓存过期时间的问题

如果缓存设置了过期时间,那么上述的所有不一致情况都只是暂时的。

但是如果没有设置过期时间,那么不一致问题就只能等到下次更新数据时解决。

所以一定要设置缓存过期时间

到此,关于"Java中怎么保证缓存一致性"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

缓存 数据 更新 数据库 问题 查询 方案 一致 场景 时间 保证 情况 概率 线程 推荐 一致性 策略 两个 中间件 之间 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 软件开发系统设计包括什么 陕西宝鸡网络安全部门 软件开发中产生的文档 网络安全应急指挥方案 节点服务器是什么意思 苏州艳秀婉网络技术有限公司 三级网络技术用c语言 数据输入管理系统软件开发 居民医保大数据库 金碟数据库文件在哪找 英国网络安全专业就业 网络安全教育公开课的策划 本科土木工程专业转软件开发 网络安全风险是指人为或自然 tt语音免费服务器 网络技术服务费怎么抵扣 软件开发管培生靠谱吗 林业局网络安全整改情况汇报 广州惠恩网络技术有限公司 汕头网络安全执法 国内外无线网络技术发展现状 北京国谷动力网络技术 服务器主机可以开多少个游戏 杭州桌面软件开发流程 鹰潭正规服务器价格 服务器的cache 新乡市明煜网络技术有限公司 mssql数据库设置永久链接 想学计算机网络安全 梦幻西游手游服务器时间怎么查看
0