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

【缓存策略】你知道 Cache Aside(缓存旁路)这个缓存策略吗

👉博主介绍: 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,WEB架构师,阿里云专家博主,华为云云享专家,51CTO 专家博主

⛪️ 个人社区:个人社区
💞 个人主页:个人主页
🙉 专栏地址: ✅ Java 中级
🙉八股文专题:剑指大厂,手撕 Java 八股文

在这里插入图片描述

文章目录

      • 1. 缓存策略 Cache Aside 是什么?
      • 2. 缓存策略 Cache Aside 的应用场景
      • 3. 缓存策略 Cache Aside 的优缺点
      • 4. 用 Java 模拟使用 Cache Aside 策略
        • 1. 引入依赖
        • 2. 配置 Redis
        • 3. 创建缓存服务
        • 4. 创建用户服务
        • 5. 创建控制器
        • 6. 启动类

1. 缓存策略 Cache Aside 是什么?

Cache Aside(缓存旁路) 是一种常见的缓存策略,其核心思想是在读取数据时,先从缓存中读取,如果缓存中没有数据,则从数据库中读取,并将数据写入缓存;在写入数据时,直接更新数据库,并从缓存中移除该数据。

具体步骤:

  1. 读取数据

    • 尝试从缓存中读取数据。
    • 如果缓存中存在数据,直接返回。
    • 如果缓存中不存在数据,从数据库中读取数据。
    • 将从数据库中读取的数据写入缓存,然后返回数据。
  2. 写入数据

    • 直接更新数据库。
    • 从缓存中移除该数据,以避免缓存中的数据与数据库中的数据不一致。

2. 缓存策略 Cache Aside 的应用场景

Cache Aside 适用于以下场景:

  1. 读多写少:适用于读取操作远多于写入操作的场景,如新闻网站的文章阅读。
  2. 数据更新不频繁:适用于数据更新不频繁,但读取非常频繁的场景。
  3. 数据一致性要求不高:适用于对数据一致性要求不高的场景,可以容忍短暂的数据不一致。
  4. 高并发读取:适用于高并发读取的场景,可以显著减轻数据库的负载。

3. 缓存策略 Cache Aside 的优缺点

优点:

  1. 性能提升:通过缓存减少对数据库的访问次数,提高读取性能。
  2. 减轻数据库压力:减少数据库的读取请求,减轻数据库的负载。
  3. 灵活性:可以在不修改业务逻辑的情况下,通过缓存策略提升系统性能。

缺点:

  1. 数据不一致:在写入数据后,缓存中的数据可能已经过期,导致短暂的数据不一致。
  2. 缓存击穿:如果大量请求同时访问同一个缓存键,而该键在缓存中不存在,会导致大量请求直接打到数据库,造成数据库压力。
  3. 缓存雪崩:如果缓存中的数据在同一时间过期,大量请求会同时打到数据库,造成数据库压力。

4. 用 Java 模拟使用 Cache Aside 策略

下面是一个简单的 Java 示例,模拟使用 Cache Aside 策略。

1. 引入依赖

pom.xml 中添加 Redis 依赖(假设使用 Redis 作为缓存):

<dependencies>
    <!-- Spring Boot Starter Data Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Boot Starter Test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
2. 配置 Redis

application.properties 中配置 Redis:

spring.redis.host=localhost
spring.redis.port=6379
3. 创建缓存服务

创建一个服务类来实现 Cache Aside 策略:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class CacheService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private UserService userService;

    public String getUserById(String userId) {
        // 尝试从缓存中读取数据
        String cachedUser = redisTemplate.opsForValue().get(userId);
        if (cachedUser != null) {
            return cachedUser;
        }

        // 如果缓存中没有数据,从数据库中读取
        String user = userService.getUserById(userId);
        if (user != null) {
            // 将数据写入缓存
            redisTemplate.opsForValue().set(userId, user);
        }

        return user;
    }

    public void updateUser(String userId, String userName) {
        // 直接更新数据库
        userService.updateUser(userId, userName);

        // 从缓存中移除该数据
        redisTemplate.delete(userId);
    }
}
4. 创建用户服务

创建一个简单的用户服务类,模拟数据库操作:

import org.springframework.stereotype.Service;

@Service
public class UserService {

    public String getUserById(String userId) {
        // 模拟从数据库中读取用户数据
        // 实际应用中,这里应该是数据库查询操作
        return "User: " + userId;
    }

    public void updateUser(String userId, String userName) {
        // 模拟更新数据库中的用户数据
        // 实际应用中,这里应该是数据库更新操作
        System.out.println("Updating user: " + userId + " to " + userName);
    }
}
5. 创建控制器

创建一个控制器类,提供 RESTful API 接口:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private CacheService cacheService;

    @GetMapping("/user")
    public String getUser(@RequestParam String id) {
        return cacheService.getUserById(id);
    }

    @PostMapping("/user")
    public String updateUser(@RequestParam String id, @RequestParam String name) {
        cacheService.updateUser(id, name);
        return "User updated: " + id + " to " + name;
    }
}
6. 启动类

创建一个启动类来启动 Spring Boot 应用:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CacheAsideApplication {

    public static void main(String[] args) {
        SpringApplication.run(CacheAsideApplication.class, args);
    }
}

运行项目

  1. 启动 Redis 服务器

    • 确保 Redis 服务器正在运行,可以通过命令 redis-server 启动。
  2. 启动 Spring Boot 应用

    • 运行 CacheAsideApplication 类的 main 方法,启动 Spring Boot 应用。
  3. 测试接口

    • 使用 Postman 或浏览器测试接口:
      • GET http://localhost:8080/user?id=1:读取用户数据。
      • POST http://localhost:8080/user?id=1&name=JohnDoe:更新用户数据。

精彩专栏推荐订阅:在下方专栏👇🏻
✅ 2023年华为OD机试真题(A卷&B卷)+ 面试指导
✅ 精选100套 Java 项目案例
✅ 面试需要避开的坑(活动)
✅ 你找不到的核心代码
✅ 带你手撕 Spring
✅ Java 初阶

在这里插入图片描述


http://www.kler.cn/a/391282.html

相关文章:

  • HarmonyOS SDK下的实践与探索
  • [Docker#8] 容器配置 | Mysql | Redis | C++ | 资源控制 | 命令对比
  • 超子物联网HAL库笔记:定时器[外部模式]篇
  • 将python下载的依赖包传到没网的服务器
  • 对称加密与非对称加密:密码学的基石及 RSA 算法详解
  • 什么是两化融合
  • 在JPA和EJB中用乐观锁解决并发问题
  • 前端模拟面试:7个JavaScript数组进阶面试题
  • 为什么go语言使用log.Fatalf打印日志导致程序退出
  • 第二天python笔记
  • 「实战应用」如何用图表控件LightningChart .NET在WPF中制作表格?(二)
  • 如何查看电脑关机时间
  • 《JavaEE进阶》----20.<基于Spring图书管理系统①(登录+添加图书)>
  • Redis7:商户查询缓存1
  • 【Linux-进程信号】信号入门介绍
  • 网络安全CTF竞赛模式、题目类别、所用工具小结
  • 比 PyTorch 更快的嵌入Python库:FastEmbed
  • django入门【05】模型介绍——字段选项(二)
  • 算法——移除元素(leetcode27)
  • el-input 正则表达式校验输入框不能输入汉字
  • 工位管理现代化:Spring Boot企业级框架
  • WPF 应用程序中使用 Prism 框架时,有多种方式可以注册服务和依赖项
  • 最大子数组和
  • vector和docker的区别?
  • RK3568平台开发系列讲解(GPIO篇)基于整数的GPIO接口
  • https网站 请求http图片报错:net::ERR_SSL_PROTOCOL_ERROR