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

news2024/9/21 10:55:49

​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 {
    @Bean
    public 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;

    @Autowired
    public 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;

    @Autowired
    public 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 {
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("myCache"); // 创建一个名为 "myCache" 的缓存
    }
}

@Service
public class DataService {
    @Autowired
    private 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;

    @Autowired
    public 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 {
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("myCache"); // 创建一个名为 "myCache" 的缓存
    }
}

@Service
public class DataService {
    @Autowired
    private 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;

    @Autowired
    public 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 {
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("myCache"); // 创建一个名为 "myCache" 的缓存
    }

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        return executor;
    }
}

@Service
public class CacheService {
    @Autowired
    private DataRepository dataRepository;

    @CachePut(value = "myCache", key = "#data.key")
    @Async
    public void writeBehind(Data data) {
        // 异步将数据写入主数据源
        writeDataToDataSource(data);
    }

    private void writeDataToDataSource(Data data) {
        dataRepository.save(data); // 写入数据到主数据源
    }
}
  • 使用缓存服务:

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

@RestController
public class MyController {
    private final CacheService cacheService;

    @Autowired
    public MyController(CacheService cacheService) {
        this.cacheService = cacheService;
    }

    @PostMapping("/data")
    public void writeData(@RequestBody Data newData) {
        cacheService.writeBehind(newData); // 异步写入数据到缓存和主数据源
    }
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2152131.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1份可以派上用场丢失数据恢复的应用程序列表

无论如何,丢失您的宝贵数据是可怕的。您的 Android 或 iOS 设备可能由于事故、硬件损坏、存储卡问题等而丢失了数据。这就是为什么我们编制了一份可以派上用场以恢复丢失数据的应用程序列表。 如果您四处走动,您大多会随身携带手机或其他移动设备。这些…

豆包Python SDK接入流程

模型与价格 豆包的模型介绍可以看豆包大模型介绍,模型价格可以看豆包定价文档里的“模型推理” - “大语言模型” - “字节跳动”部分。 推荐使用以下模型: Doubao-lite-32k:每百万 token 的输入价格为 0.3 元,输出价格为 0.6 元…

vue组件($refs对象,动态组件,插槽,自定义指令)

一、ref 1.ref引用 每个vue组件实例上&#xff0c;都包含一个$refs对象&#xff0c;里面存储着对应dom元素或组件的引用。默认情况下&#xff0c;组件的$refs指向一个空对象。 2.使用ref获取dom元素的引用 <template><h3 ref"myh3">ref组件</h3&g…

手机切换IP简单方法:掌握技巧,轻松实现IP变换‌

在当今的数字化时代&#xff0c;IP地址作为网络身份的重要标识&#xff0c;对于网络访问、数据传输等方面都起着至关重要的作用。然而&#xff0c;在某些特定场景下&#xff0c;我们可能需要切换手机的IP地址&#xff0c;以满足不同的网络需求。本文将为大家介绍几种手机切换IP…

Linux —— 多线程

一、本篇重点 1.了解线程概念&#xff0c;理解线程与进程区别与联系 2.理解和学会线程控制相关的接口和操作 3.了解线程分离与线程安全的概念 4.学会线程同步。 5.学会互斥量&#xff0c;条件变量&#xff0c;posix信号量&#xff0c;以及读写锁 6.理解基于读写锁的读者写…

Kafka 3.0.0集群部署教程

1、集群规划 主机名 ip地址 node.id process.roles kafka1 192.168.0.29 1 broker,controller Kafka2 192.168.0.30 2 broker,controller Kafka3 192.168.0.31 3 broker,controller 将kafka包上传以上节点/app目录下 mkdir /app 解压kafka包 tar -zxvf kafka_…

BLE 协议之链路层

目录 一、前言二、状态和角色三、Air Interface Packets1、Preamble 字段2、Access Address 字段2.1 静态地址2.2 私有地址 3、PDU 字段3.1 Advertising Channel PDU3.1.1 Header 字段3.1.2 Payload 字段 3.2 Data Channel PDU3.2.1 Header 字段3.2.2 Payload 字段 4、CRC 字段…

【UE5】将2D切片图渲染为体积纹理,最终实现使用RT实时绘制体积纹理【第一篇-原理】

如果想直接制作&#xff0c;请看【第二篇】内容 这次做一个这样的东西&#xff0c;通过在2DRT上实时绘制&#xff0c;生成动态的体积纹理&#xff0c;也就是可以runtime的VDB 设想的文章流程: 对原理进行学习制作体积渲染制作实时绘制 第一篇&#xff08;本篇&#xff09;是对“…

Spring MVC 基础 : 文件、cookies的接收 ,REST响应

一、接受文件 在 Spring MVC 中&#xff0c;可以使用 RequestPart 注解来接收文件。这个注解常用于处理复杂的请求&#xff0c;如同时发送 JSON 数据和文件。RequestPart 非常适用于多部分请求&#xff08;multipart requests&#xff09;&#xff0c;这在单个请求中同时发送文…

法定退休年龄计算器,看看你还有多少年退休?

最近延迟退休上了微博热搜&#xff0c;从2025年开始实行。 分享个法定退休年龄计算器&#xff0c;看看你还有多少年退休&#xff1f; 官方出品的计算器&#xff0c;网站地址 https://si.12333.gov.cn/304647.jhtml 输入出生日期和性别就可以。 当然也可以在微信的城市服务。…

基于asp.net固定资产管理系统设计与实现

博主介绍&#xff1a;专注于Java vue .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的…

JZ2440开发板——S3C2440的UART

以下内容源于韦东山课程的学习与整理&#xff0c;如有侵权请告知删除。 一、UART硬件简介 UART&#xff0c;全称是“Universal Asynchronous Receiver Transmitter”&#xff0c;即“通用异步收发器”&#xff0c;也就是我们日常说的“串口”。 它在嵌入式中用途非常广泛&…

【计算机网络篇】物理层

本文主要介绍计算机网络第二章节的物理层&#xff0c;文中的内容是我认为的重点内容&#xff0c;并非所有。参考的教材是谢希仁老师编著的《计算机网络》第8版。跟学视频课为河南科技大学郑瑞娟老师所讲计网。 文章目录 &#x1f3af;一.基本概念及公式 &#x1f383;基本概念…

力扣-1035不相交的线(Java详细题解)

题目链接&#xff1a;力扣-1035不相交的线 前情提要&#xff1a; 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 dp五部曲。 1.确定dp数组和i下标的含义。 2.确定递推公式。 3.dp初始化。 4.确定dp的遍历顺序。 5.如果没有ac打印dp数组 利于debug。 每一…

安全基础学习-AES128加密算法

前言 AES&#xff08;Advanced Encryption Standard&#xff09;是对称加密算法的一个标准&#xff0c;主要用于保护电子数据的安全。AES 支持128、192、和256位密钥长度&#xff0c;其中AES-128是最常用的一种&#xff0c;它使用128位&#xff08;16字节&#xff09;的密钥进…

充电宝什么品牌比较好?五大性价比高充电宝品牌推荐!

在这个电子设备无处不在的时代&#xff0c;充电宝已成为我们生活中不可或缺的重要配件。无论是通勤、旅行还是户外休闲&#xff0c;充电宝都能为我们的手机、平板等提供及时的电量补充&#xff0c;确保我们时刻保持在线。一个安全可靠的充电宝&#xff0c;不仅能为我们的设备提…

GRU(门控循环单元)的原理与代码实现

1.GRU的原理 1.1重置门和更新门 1.2候选隐藏状态 1.3隐状态 2. GRU的代码实现 #导包 import torch from torch import nn import dltools#加载数据 batch_size, num_steps 32, 35 train_iter, vocab dltools.load_data_time_machine(batch_size, num_steps)#封装函数&…

VScode开发GD32移植(标准库通用),保姆级!!!!!!!

VScode开发GD32移植(标准库通用)&#xff0c;保姆级&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 文章目录 VScode开发GD32移植(标准库通用)&#xff0c;保姆级&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#…

[产品管理-30]:NPDP新产品开发 - 29 - 产品生命周期管理 - 可持续产品创新

目录 一、可持续开发与可持续创新 可持续开发 可持续创新 可持续开发与可持续创新的关系 二、循环经济 1、循环经济的定义 2、循环经济的起源与发展 3、循环经济的原则 4、循环经济的实践案例 5、循环经济的意义与展望 三、三重底线 1. 财务底线 - 企业。赚钱 2. …

11. DPO 微调示例:根据人类偏好优化LLM大语言模型

在部署大模型之后&#xff0c;我们必然要和微调打交道。现在大模型的微调有非常多的方法&#xff0c;过去的文章中提到的微调方法通常依赖于问题和答案对&#xff0c;标注成本较高。 2023 年所提出的 Direct Preference Optimization&#xff08;DPO&#xff09;为我们提供了一…