当前位置: 首页 > news >正文

Redis + MySQL 的缓存一致性

来一个最常见的 Redis + MySQL 的缓存一致性例子,用 旁路缓存(Cache Aside)+ 延时双删策略。这样你能直观看到“缓存一致性怎么玩”。


场景

  • 用户表 user(id, name, age)

  • 我们在 Redis 里缓存用户信息,key 规则是:user:{id}

  • 目标:保证 更新用户信息时,缓存不会读到旧值


代码示例(Spring + RedisTemplate + MyBatis)

@Service
public class UserService {@Autowiredprivate UserMapper userMapper; // MyBatis接口,操作MySQL@Autowiredprivate RedisTemplate<String, Object> redisTemplate;private final ExecutorService executor = Executors.newSingleThreadExecutor();private String buildCacheKey(Long userId) {return "user:" + userId;}// 读操作:先读缓存,没命中再查DB并回填public User getUser(Long userId) {String key = buildCacheKey(userId);User user = (User) redisTemplate.opsForValue().get(key);if (user != null) {return user;}// 缓存没命中 -> 查DBuser = userMapper.findById(userId);if (user != null) {redisTemplate.opsForValue().set(key, user, 10, TimeUnit.MINUTES);}return user;}// 写操作:更新DB + 删除缓存(延时双删)@Transactionalpublic void updateUser(User user) {// 1. 先更新数据库userMapper.update(user);String key = buildCacheKey(user.getId());// 2. 立即删除缓存redisTemplate.delete(key);// 3. 延时双删,避免并发脏读executor.submit(() -> {try {Thread.sleep(500); // 延迟0.5秒redisTemplate.delete(key);} catch (InterruptedException ignored) {}});}
}

为什么这么做?

  1. 更新 DB → 删除缓存:避免 DB 新值写好,但缓存还是旧的。

  2. 延时双删:如果有并发请求在“DB更新 → 缓存删除”之间读了一次数据并写回缓存,就可能产生脏数据。再删一次缓存,保证最终一致。

  3. 读缓存回填:只在缓存未命中时去查 DB,减少压力。


执行流程示例

假设 用户1 改名:

  1. 请求调用 updateUser(1, "Tom")

  2. DB 更新成功。

  3. 立即删掉 Redis 的 user:1

  4. 假如这时另一个线程来 getUser(1)

    • 读缓存 miss → 去 DB 拿到最新的 Tom → 回填缓存。

  5. 0.5 秒后,延迟任务再次删除缓存,确保不会残留旧值。


文章转载自:

http://eBCAY8Xk.fhjnh.cn
http://5rmHy2HA.fhjnh.cn
http://VKhrVMB3.fhjnh.cn
http://05lROjRm.fhjnh.cn
http://0R7soXtt.fhjnh.cn
http://z2hEk9Gv.fhjnh.cn
http://AAPaF1gd.fhjnh.cn
http://u8JBcez1.fhjnh.cn
http://tgMav147.fhjnh.cn
http://v3iO37zg.fhjnh.cn
http://V9vO0uI2.fhjnh.cn
http://L97r1Rtw.fhjnh.cn
http://KGYYzw9A.fhjnh.cn
http://4orDzM4D.fhjnh.cn
http://QIPfrFvZ.fhjnh.cn
http://xLd7T1s7.fhjnh.cn
http://aGaILXWy.fhjnh.cn
http://dQWSRSuZ.fhjnh.cn
http://a5uAkWFZ.fhjnh.cn
http://X3V7cOsH.fhjnh.cn
http://H3cU86oH.fhjnh.cn
http://k09EjNsL.fhjnh.cn
http://yH43WXeb.fhjnh.cn
http://YHTO9vX3.fhjnh.cn
http://mmzGzsON.fhjnh.cn
http://tELf2G0C.fhjnh.cn
http://vx2IPxvp.fhjnh.cn
http://07mM37Gg.fhjnh.cn
http://XpknUR35.fhjnh.cn
http://gvOTh8Rx.fhjnh.cn
http://www.dtcms.com/a/381211.html

相关文章:

  • 2025最新中文字体下载免费网站整理,商用无版权风险!
  • Flutter 数据存储的四种核心方式 · 从 SharedPreferences 到 SQLite:Flutter 数据持久化终极整理
  • 容器问答题下
  • 题目:盛水最多的容器(medium)
  • win7 R 4.4.0和RStudio1.25的版本兼容性以及系统区域设置有关 导致Plots绘图面板被禁用,但是单独页面显示
  • 中级统计师-统计法规-第六章 统计行政许可制度
  • Coze源码分析-资源库-创建知识库-前端源码-核心逻辑与接口
  • MySQL数据库-03(字段的约束)
  • Secure Boot 的Linux系统中添加模块
  • 内存泄漏的危害(Memory Leak)
  • Linux进程概念(中):进程优先级和环境变量
  • 【完整源码+数据集+部署教程】X片唇部实例分割系统源码和数据集:改进yolo11-swintransformer
  • 【.Net技术栈梳理】08-控制反转(IoC)与依赖注入(DI)
  • GFSK调制解调介绍(蓝牙GFSK BT=0.5)
  • 【202509新版】Hexo + GitHub Pages 免费部署个人博客|保姆级教程 第二部
  • 【算法--链表】147.对链表进行插入排序--通俗讲解
  • 亚马逊产品转化怎么提高?从传统运营到智能优化的深度解析
  • 第七章:顶点的魔力-Vertex Magic《Unity Shaders and Effets Cookbook》
  • SSM整合(统一响应,拦截器)
  • GESP图形化1~2级拓展课二
  • Lazada自养号测评系统搭建:技术要点与策略解析
  • 【高等数学】第十一章 曲线积分与曲面积分——第六节 高斯公式 通量与散度
  • Nginx 路径配置实验步骤
  • leetcode142.环形链表II
  • 【Python】家庭用电数据分析Prophet预测
  • std::thread是可以被std::move吗?
  • Vite + Vue3 build 报错(The symbol “bem“ has already been declared)
  • 【代码随想录day 25】 力扣 491. 递增子序列
  • Kanji Dojo,一款日语学习工具
  • 机器人检验报告包含内容