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

实战Redis与MySQL双写一致性的缓存模式

​Redis和MySQL都是常用的数据存储系统,它们各自有自己的优缺点。在实际应用中,我们可能需要将它们结合起来使用,比如将Redis作为缓存,MySQL作为持久化存储。

在这种情况下,我们需要保证Redis和MySQL的数据一致性,也就是当数据在Redis中进行修改时,也要相应地在MySQL中进行修改,反之亦然。


Cache-Aside Pattern

Cache-Aside Pattern(也称为 Lazy-Loading 缓存模式)是一种常见的缓存设计模式,用于在应用程序中手动管理缓存数据。在这种模式下,应用程序负责在需要的时候将数据加载到缓存中,以便提高数据的访问速度和性能。

Cache-Aside 模式的工作流程如下:

1. 读取数据

当应用程序需要读取数据时,它首先会检查缓存中是否存在所需数据。如果数据存在于缓存中,应用程序直接从缓存中获取数据。如果数据不在缓存中,应用程序会从主数据源(如数据库)中获取数据,并将数据加载到缓存中。

2. 写入数据

当应用程序执行写操作(如创建、更新、删除)时,它首先会更新主数据源中的数据。然后,应用程序手动更新或使缓存中的相关数据失效,以确保缓存中的数据保持与主数据源一致。

3. 缓存失效

在 Cache-Aside 模式中,缓存失效是由应用程序来管理的。这意味着应用程序需要根据数据的更新频率和业务需求,手动决定何时使缓存数据失效,以便在下次访问时重新加载最新的数据。

4.代码示例

基于Spring Cloud的Cache-Aside Pattern缓存模式可以通过Spring框架的缓存抽象和Spring Cloud的服务组件来实现。在这种模式下,应用程序负责手动地管理缓存数据的加载和失效。以下是一个基于Spring Cloud的Cache-Aside Pattern缓存模式的伪代码示例:

  • 定义缓存配置和服务

首先,需要定义一个缓存配置类和一个缓存服务类来管理缓存和数据读写操作。

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@EnableCaching
public class CacheConfig {@Beanpublic CacheManager cacheManager() {return new ConcurrentMapCacheManager("myCache"); // 创建一个名为 "myCache" 的缓存}
}@Service
public class CacheService {private final Cache cache;public CacheService(CacheManager cacheManager) {this.cache = cacheManager.getCache("myCache"); // 获取名为 "myCache" 的缓存}public Object getDataFromCache(String key) {Cache.ValueWrapper valueWrapper = cache.get(key);if (valueWrapper != null) {return valueWrapper.get();}return null;}public void putDataInCache(String key, Object data) {cache.put(key, data); // 将数据加载到缓存中}public void invalidateCache(String key) {cache.evict(key); // 使缓存中的数据失效}
}
  • 使用缓存服务

业务逻辑中,可以使用缓存服务来读取和写入数据。

@Service
public class BusinessService {private final DataService dataService;private final CacheService cacheService;@Autowiredpublic BusinessService(DataService dataService, CacheService cacheService) {this.dataService = dataService;this.cacheService = cacheService;}public Object fetchData(String key) {Object cachedData = cacheService.getDataFromCache(key);if (cachedData != null) {return cachedData;} else {Object newData = dataService.fetchDataFromDataSource(key);cacheService.putDataInCache(key, newData);return newData;}}public void updateData(String key, Object newData) {dataService.updateDataSource(key, newData); // 更新主数据源cacheService.invalidateCache(key); // 使缓存中的数据失效}
}
  • 使用示例:

可以通过业务服务来读取和更新数据。

@RestController
public class MyController {private final BusinessService businessService;@Autowiredpublic MyController(BusinessService businessService) {this.businessService = businessService;}@GetMapping("/data/{key}")public Object getData(@PathVariable String key) {return businessService.fetchData(key); // 从缓存或数据源获取数据}@PostMapping("/data/{key}")public void updateData(@PathVariable String key, @RequestBody Object newData) {businessService.updateData(key, newData); // 更新数据并使缓存失效}
}

在这个示例中,我们使用了Spring框架的缓存注解和缓存管理器来实现Cache-Aside Pattern。通过CacheService来操作缓存数据的读写,通过BusinessService来处理业务逻辑,保证从缓存读取数据或将数据加载到缓存时的一致性。


Read-Through/Write through

Read-Through和Write-Through是两种常见的缓存模式,用于更有效地管理缓存中的数据读取和写入操作。它们分别用于在数据被读取和写入时自动操作缓存和主数据源。下面我将详细介绍这两种缓存模式,并提供基于Spring的伪代码示例。

Read-Through缓存模式

在Read-Through缓存模式中,当应用程序尝试读取缓存中的数据时,如果缓存中不存在该数据,会自动从主数据源(如数据库)中读取数据,并将数据加载到缓存中,以便下次读取时能够直接从缓存中获取。

工作流程:

  1. 应用程序尝试从缓存读取数据。

  2. 如果缓存中存在数据,应用程序直接从缓存中获取。

  3. 如果缓存中不存在数据,应用程序从主数据源中读取数据,并将数据加载到缓存中。

Write-Through缓存模式

在Write-Through缓存模式中,当应用程序执行写操作时,数据会首先被写入缓存,然后自动同步更新到主数据源(如数据库)中,以保持数据的一致性。

工作流程:

  1. 应用程序执行写操作,将数据写入缓存。

  2. 缓存自动将写入的数据同步更新到主数据源中。

代码示例

基于Spring Cloud的Read-Through和Write-Through缓存模式可以通过Spring框架的缓存抽象和Spring Cloud的服务组件来实现。这两种模式是更为自动化的缓存管理方法,它们分别处理数据的读取和写入操作,无需应用程序手动介入。以下是基于Spring Cloud的伪代码示例:

Read-Through缓存模式示例

  • 定义缓存配置和服务:

首先,需要定义一个缓存配置类和一个数据服务类,用于管理缓存和数据读取操作。

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@EnableCaching
public class CacheConfig {@Beanpublic CacheManager cacheManager() {return new ConcurrentMapCacheManager("myCache"); // 创建一个名为 "myCache" 的缓存}
}@Service
public class DataService {@Autowiredprivate DataRepository dataRepository; // 假设有一个数据仓库@Cacheable(value = "myCache", key = "#key")public Data getData(String key) {return dataRepository.findById(key).orElse(null);}
}
  • 使用缓存服务:

在业务逻辑中,可以使用缓存服务来读取数据。

@RestController
public class MyController {private final DataService dataService;@Autowiredpublic MyController(DataService dataService) {this.dataService = dataService;}@GetMapping("/data/{key}")public Data getData(@PathVariable String key) {return dataService.getData(key); // 从缓存或数据仓库获取数据}
}

Write-Through缓存模式示例

  • 定义缓存配置和服务:

同样,你需要定义一个缓存配置类和一个数据服务类,用于管理缓存和数据写入操作。

@Configuration
@EnableCaching
public class CacheConfig {@Beanpublic CacheManager cacheManager() {return new ConcurrentMapCacheManager("myCache"); // 创建一个名为 "myCache" 的缓存}
}@Service
public class DataService {@Autowiredprivate DataRepository dataRepository; // 假设有一个数据仓库@CachePut(value = "myCache", key = "#data.key")public Data updateData(Data data) {dataRepository.save(data); // 更新数据到数据仓库return data;}
}
  • 使用缓存服务:

可以使用缓存服务来写入数据。

@RestController
public class MyController {private final DataService dataService;@Autowiredpublic MyController(DataService dataService) {this.dataService = dataService;}@PostMapping("/data")public Data updateData(@RequestBody Data newData) {return dataService.updateData(newData); // 写入数据到缓存和数据仓库}
}

在这些示例中,@Cacheable@CachePut注解用于实现Read-Through和Write-Through缓存模式。DataService类负责在数据读取和写入时处理缓存和主数据源之间的同步。


Write behind

Write-Behind缓存模式是一种缓存设计模式,它将写入操作先缓存起来,然后在合适的时机异步地将数据写入主数据源(例如数据库)。这种模式可以提高写入操作的性能和响应时间,同时通过异步写入减少主数据源的负载。

工作原理

  1. 当应用程序执行写入操作时,数据首先会被写入缓存,然后标记为"脏数据"。
  2. 后台异步线程定期或在特定事件触发时,将"脏数据"批量写入主数据源。

这种模式在需要频繁写入操作的场景中特别有用,因为它将写入操作进行了批处理,减少了与主数据源的交互次数,从而提高了性能。

Write-Behind缓存模式的优点

  • 提高写入操作的性能:写入操作首先在缓存中完成,减少了对主数据源的直接写入次数,从而提高了写入性能。
  • 减轻主数据源负载:异步写入减少了主数据源的负载,特别是在高并发的情况下。
  • 高吞吐量:通过批量写入的方式,可以提高系统的吞吐量。

代码示例

基于Spring Cloud的Write-Behind缓存模式可以使用Spring框架的缓存抽象和Spring Cloud的服务组件来实现。这种模式可以提高写入操作的性能和响应时间,同时通过异步写入减少主数据源的负载。以下是基于Spring Cloud的Write-Behind缓存模式的伪代码示例:

  • 定义缓存配置和服务:

首先,需要定义一个缓存配置类和一个缓存服务类,用于管理缓存和数据写入操作。

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;@Configuration
@EnableCaching
@EnableAsync
public class CacheConfig {@Beanpublic CacheManager cacheManager() {return new ConcurrentMapCacheManager("myCache"); // 创建一个名为 "myCache" 的缓存}@Beanpublic ThreadPoolTaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(25);return executor;}
}@Service
public class CacheService {@Autowiredprivate DataRepository dataRepository;@CachePut(value = "myCache", key = "#data.key")@Asyncpublic void writeBehind(Data data) {// 异步将数据写入主数据源writeDataToDataSource(data);}private void writeDataToDataSource(Data data) {dataRepository.save(data); // 写入数据到主数据源}
}
  • 使用缓存服务:

在业务逻辑中,可以使用缓存服务来写入数据。

@RestController
public class MyController {private final CacheService cacheService;@Autowiredpublic MyController(CacheService cacheService) {this.cacheService = cacheService;}@PostMapping("/data")public void writeData(@RequestBody Data newData) {cacheService.writeBehind(newData); // 异步写入数据到缓存和主数据源}
}

在这个示例中,我们使用了Spring框架的@CachePut注解和异步任务来实现Write-Behind缓存模式。CacheService负责在数据写入缓存的同时,异步地将数据写入主数据源。这样可以提高写入性能,并减轻主数据源的负载。

相关文章:

实战Redis与MySQL双写一致性的缓存模式

​Redis和MySQL都是常用的数据存储系统,它们各自有自己的优缺点。在实际应用中,我们可能需要将它们结合起来使用,比如将Redis作为缓存,MySQL作为持久化存储。 在这种情况下,我们需要保证Redis和MySQL的数据一致性&…...

KVM环境下制作ubuntu qcow2格式镜像

如果是Ubuntu KVM环境是VMware虚拟机,需要CPU开启虚拟化 1、配置镜像源 wget -O /etc/apt/sources.list https://www.qingtongqing.cc/ubuntu/sources.list2、安装kvm qemu-img libvirt kvm虚拟化所需环境组件 apt -y install qemu-kvm virt-manager libvirt-da…...

基于SpringBoot+Vue的高校竞赛管理系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…...

PHP发邮件教程:配置SMTP服务器发送邮件?

PHP发邮件的几种方式?如何使用PHP通过SMTP协议发信? PHP作为一种广泛使用的服务器端脚本语言,提供了多种方式来发送邮件。AokSend将详细介绍如何通过配置SMTP服务器来实现PHP发邮件教程的核心内容。 PHP发邮件教程:设置参数 这…...

SpringBootWeb增删改查入门案例

前言 为了快速入门一个SpringBootWeb项目,这里就将基础的增删改查的案例进行总结,作为对SpringBootMybatis的基础用法的一个巩固。 准备工作 需求说明 对员工表进行增删改查操作环境搭建 准备数据表 -- 员工管理(带约束) create table emp (id int …...

pytorch实现RNN网络

目录 1.导包 2. 加载本地文本数据 3.构建循环神经网络层 4.初始化隐藏状态state 5.创建随机的数据,检测一下代码是否能正常运行 6. 构建一个完整的循环神经网络 7.模型训练 8.个人知识点理解 1.导包 import torch from torch import nn from torch.nn imp…...

智能工厂的软件设计 “程序program”表达式,即 接口模型的代理模式表达式

Q1、前面将“智能工厂的软件设计”中绝无仅有的“程序”视为 专注于 给定的某个单一面(语言面/逻辑面/数学面)中的 问题,专注于分析问题和解决问题的程序活动的组织,每一面都是一个“组织者”就像一个“独角兽”,并提出…...

leetcode 难度【简单模式】标签【数据库】题型整理大全

文章目录 175. 组合两个表181. 超过经理收入的员工182. 查找重复的电子邮箱COUNT(*)COUNT(*) 与 COUNT(column) 的区别 where和vaing之间的区别用法 183.从不订购的客户196.删除重复的电子邮箱197.上升的温度511.游戏玩法分析I512.游戏玩法分析II577.员工奖金584.寻找用户推荐人…...

利士策分享,自我和解:通往赚钱与内心富足的和谐之道

利士策分享,自我和解:通往赚钱与内心富足的和谐之道 在这个快节奏、高压力的时代,我们往往在追求物质财富的同时,忽略了内心世界的和谐与平衡。 赚钱,作为现代生活中不可或缺的一部分,它不仅仅是生存的手段…...

【物联网】深入解析时序数据库TDengine及其Java应用实践

文章目录 一、什么是时序数据库?二、TDengine简介三、TDengine的Java应用实践(1)环境准备(2)数据插入(3)数据查询 一、什么是时序数据库? 时序数据库(Time-Series Datab…...

2023北华大学程序设计新生赛部分题解

时光如流水般逝去,我已在校园中奋战大二!(≧▽≦) 今天,静静回顾去年的新生赛,心中涌起无尽感慨,仿佛那段青春岁月如烟花般绚烂。✧。(≧▽≦)。✧ 青春就像一场燃烧的盛宴,激情澎湃&…...

PPP的配置

概述:PPP模式,即公私合作模式(Public-Private Partnership),是一种公共部门与私营部门合作的模式。 一、实验拓扑 实验一:PPP基本功能 实验步骤: (1)配置AR1的接口IP地…...

回溯算法总结篇

组合问题:N个数里面按一定规则找出k个数的集合 如果题目要求的是组合的具体信息,则只能使用回溯算法,如果题目只是要求组合的某些最值,个数等信息,则使用动态规划(比如求组合中元素最少的组合,…...

机器学习-点击率预估-论文速读-20240916

1. [经典文章] 特征交叉: Factorization Machines, ICDM, 2010 分解机(Factorization Machines) 摘要 本文介绍了一种新的模型类——分解机(FM),它结合了支持向量机(SVM)和分解模型的优点。与…...

【leetcode】堆习题

215.数组中的第K个最大元素 给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。 请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输…...

前端大模型入门:编码(Tokenizer)和嵌入(Embedding)解析 - llm的输入

LLM的核心是通过对语言进行建模来生成自然语言输出或理解输入,两个重要的概念在其中发挥关键作用:Tokenizer 和 Embedding。本篇文章将对这两个概念进行入门级介绍,并提供了针对前端的js示例代码,帮助读者理解它们的基本原理/作用和如何使用。 1. 什么是…...

一文读懂 JS 中的 Map 结构

你好,我是沐爸,欢迎点赞、收藏、评论和关注。 上次聊了 Set 数据结构,今天我们聊下 Map,看看它与 Set、与普通对象有什么区别?下面直接进入正题。 一、Set 和 Map 有什么区别? Set 是一个集合&#xff0…...

C++校招面经(二)

欢迎关注 0voice GitHub 6、 C 和 Java 区别(语⾔特性,垃圾回收,应⽤场景等) 指针: Java 语⾔让程序员没法找到指针来直接访问内存,没有指针的概念,并有内存的⾃动管理功能,从⽽…...

Python Web 面试题

1 Web 相关 get 和 post 区别 get: 请求数据在 URL 末尾,URL 长度有限制 请求幂等,即无论请求多少次,服务器响应始终相同,这是因为 get 至少获取资源,而不修改资源 可以被浏览器缓存,以便以后…...

java日志框架之JUL(Logging)

文章目录 一、JUL简介1、JUL组件介绍 二、Logger快速入门三、Logger日志级别1、日志级别2、默认级别info3、原理分析4、自定义日志级别5、日志持久化(保存到磁盘) 三、Logger父子关系四、Logger配置文件 一、JUL简介 JUL全程Java Util Logging&#xff…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...

SpringTask-03.入门案例

一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...