掌握 Spring Boot 中的缓存:技术和最佳实践

news2024/12/26 22:43:26

缓存是一种用于将经常访问的数据临时存储在更快的存储层(通常在内存中)中的技术,以便可以更快地满足未来对该数据的请求,从而提高应用程序的性能和效率。在 Spring Boot 中,缓存是一种简单而强大的方法,可以通过减少数据库命中、API 调用或昂贵的计算来增强应用程序性能。
在这里插入图片描述

为什么要使用缓存?

  • 改进的性能:缓存通过从更快的缓存中提供频繁请求的数据而不是重新计算或重新获取数据来减少响应时间。
  • 减少资源负载:减少数据库或外部服务等底层资源的负载。
  • 成本效率:当您的应用程序在云中运行或使用第三方服务时,减少 API 调用或数据库访问次数可以节省成本。
  • 更好的可扩展性:通过缓存,您可以通过降低后端服务的压力来允许应用程序处理更多并发请求。

在这里插入图片描述

Spring Boot中的缓存

Spring Boot 使用@Cacheable@CachePut@CacheEvict注释等提供了一个用于缓存的抽象层。这种抽象允许您轻松集成不同的缓存实现(例如 EhCache、Hazelcast、Redis 等)。
Spring Boot 缓存中的关键概念

  • 缓存存储:这是数据缓存的实际位置(内存中、Redis、EhCache 等)。
  • 缓存键:用于存储和检索缓存数据的标识符。
  • 缓存值:与缓存键关联的实际数据。
  • 缓存管理器:用于管理不同缓存实现的 Spring 抽象。

缓存操作

  • @Cacheable :缓存方法的结果。
  • @CachePut :更新缓存而不影响方法的执行。
  • @CacheEvict :从缓存中删除条目。

2.2. Spring Boot 缓存注解

@EnableCaching :此注释启用 Spring Boot 中的缓存支持。

  • 要启用缓存,您只需使用@EnableCaching注释您的主配置类。
@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@Cacheable :该注解用于缓存方法调用的结果。当调用@Cacheable注解的方法时,Spring会检查结果是否已经在缓存中。如果是,则返回缓存的值;否则,执行该方法,并将结果存储在缓存中。

@Cacheable("employees")
public Employee getEmployeeById(Long id) {
    // Simulate expensive operation
    return employeeRepository.findById(id).orElse(null);
}

@CacheEvict :这用于从缓存中删除条目。您可以指定要逐出哪个键或缓存。

@CacheEvict(value = "employees", allEntries = true)
public void clearCache() {
    // Clears all cache entries for 'employees'
}

@CachePut :与@Cacheable不同,此注释确保方法始终执行,但用结果更新缓存。

@CachePut(value = "employees", key = "#employee.id")
public Employee updateEmployee(Employee employee) {
    return employeeRepository.save(employee);
}

缓存机制工作流程

步骤1 :向带有@Cacheable注释的方法发出请求。

步骤 2 :Spring 检查缓存中的数据是否可用:

  • 如果,则返回缓存的值而不执行该方法。
  • 如果没有,则执行该方法,缓存结果,然后返回结果。

步骤3 :对于@CachePut ,执行该方法,并且无论key是否已经存在于缓存中,结果都会被缓存。

步骤4 :对于@CacheEvict ,Spring根据提供的缓存键删除缓存条目(或清除整个缓存)。

在 Spring Boot 中配置缓存存储

Spring Boot 支持多个缓存提供程序,例如:

  • ConcurrentMapCache (默认,内存缓存)
  • EhCache 高速缓存
  • Hazelcast 榛卡斯特
  • Redis 雷迪斯
  • Caffeine 咖啡因

生产场景用到的缓存中间件

在这里插入图片描述

如何在生产中应用

  • 由于其性能、集群功能、灵活性和广泛的功能, Redis通常是大多数生产环境的最佳缓存提供程序。
  • 如果您正在使用分布式系统或微服务,Redis 或Hazelcast因其可扩展性而更适合。
  • 对于易于集成和本地缓存就足够的小型单节点应用程序, EhCacheCaffeine会更易于使用。

为了演示在带有 MySQL 的 Spring Boot 应用程序中使用EhCache 的完整示例,我们将构建一个基本应用程序,该应用程序对Employee实体执行 CRUD 操作,并利用缓存来获取、更新和删除操作。

设置项目

We’ll use the following: 我们将使用以下内容:

  • 用于数据库交互的Spring Boot Starter Data JPA
  • EhCache作为缓存提供者。
  • MySQL作为数据库。

依赖关系

在您的pom.xml中,包含必要的依赖项:

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

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

    <!-- EhCache -->
    <dependency>
        <groupId>org.ehcache</groupId>
        <artifactId>ehcache</artifactId>
    </dependency>

    <!-- MySQL Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

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

    <!-- Lombok (for boilerplate code) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>

EhCache配置

src/main/resources目录下创建**ehcache.xml**文件:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <cache name="employees"
           maxEntriesLocalHeap="1000"
           timeToLiveSeconds="3600"
           memoryStoreEvictionPolicy="LRU">
    </cache>
</ehcache>

应用程序属性

application.properties中,配置 MySQL 并启用 EhCache:

# MySQL Configuration
spring.datasource.url=jdbc:mysql://localhost:3306/employee_db
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

# EhCache Configuration
spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:ehcache.xml

实体类

定义Employee实体类:

package com.example.caching.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String department;
    private double salary;
}

存储库接口

创建一个扩展JpaRepository EmployeeRepository接口:

package com.example.caching.repository;

import com.example.caching.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;

public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

服务层

EmployeeService中实现缓存逻辑:

package com.example.caching.service;

import com.example.caching.entity.Employee;
import com.example.caching.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository employeeRepository;

    // Fetch employee and cache the result
    @Cacheable(value = "employees", key = "#id")
    public Employee getEmployeeById(Long id) {
        System.out.println("Fetching from database...");
        Optional<Employee> employee = employeeRepository.findById(id);
        return employee.orElse(null);
    }

    // Update employee and update cache
    @CachePut(value = "employees", key = "#employee.id")
    public Employee updateEmployee(Employee employee) {
        System.out.println("Updating employee in database and cache...");
        return employeeRepository.save(employee);
    }

    // Delete employee and evict cache
    @CacheEvict(value = "employees", key = "#id")
    public void deleteEmployee(Long id) {
        System.out.println("Deleting employee from database and evicting cache...");
        employeeRepository.deleteById(id);
    }

    // Clear entire cache for 'employees'
    @CacheEvict(value = "employees", allEntries = true)
    public void clearCache() {
        System.out.println("Cache cleared!");
    }
}

控制器层

创建一个 REST 控制器来公开 CRUD 端点:

package com.example.caching.controller;

import com.example.caching.entity.Employee;
import com.example.caching.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/employees")
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    // Fetch employee by ID
    @GetMapping("/{id}")
    public Employee getEmployee(@PathVariable Long id) {
        return employeeService.getEmployeeById(id);
    }

    // Update employee
    @PutMapping("/{id}")
    public Employee updateEmployee(@PathVariable Long id, @RequestBody Employee employee) {
        employee.setId(id);
        return employeeService.updateEmployee(employee);
    }

    // Delete employee
    @DeleteMapping("/{id}")
    public void deleteEmployee(@PathVariable Long id) {
        employeeService.deleteEmployee(id);
    }

    // Clear cache
    @DeleteMapping("/cache/clear")
    public void clearCache() {
        employeeService.clearCache();
    }
}

主要应用类

通过添加@EnableCaching在 Spring Boot 应用程序中启用缓存:

package com.example.caching;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class CachingApplication {

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

测试应用程序

启动应用程序并使用 Postman(或类似工具)来访问以下端点:

获取员工(缓存结果):

GET http://localhost:8080/api/employees/{id}

第一个请求将从数据库中获取员工并缓存结果。后续对同一员工 ID 的请求将从缓存中返回结果。

更新员工(更新缓存):

PUT http://localhost:8080/api/employees/{id}

更新数据库和缓存中的员工。

删除员工(删除缓存):

DELETE http://localhost:8080/api/employees/{id}

从数据库中删除员工并删除缓存条目。

Clear Cache: 清空缓存:

DELETE http://localhost:8080/api/employees/cache/clear

清除employees的所有缓存条目。

这个完整的 Spring Boot 示例演示了如何将EhCache与 MySQL 数据库集成以缓存 CRUD 操作。 @Cacheable@CachePut@CacheEvict注释无缝处理缓存,通过减少数据库负载来提高性能。

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

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

相关文章

Unity 模拟百度地图,使用鼠标控制图片在固定区域内放大、缩小、鼠标左键拖拽移动图片

效果展示&#xff1a; 步骤流程&#xff1a; 1.使用的是UGUI&#xff0c;将下面的脚本拖拽到图片上即可。 using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems;public class CheckImage : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragH…

基础入门-Web应用OSS存储负载均衡CDN加速反向代理WAF防护部署影响

知识点&#xff1a; 1、基础入门-Web应用-防护产品-WAF保护 2、基础入门-Web应用-加速服务-CDN节点 3、基础入门-Web应用-文件托管-OSS存储 4、基础入门-Web应用-通讯服务-反向代理 5、基础入门-Web应用-运维安全-负载均衡 一、演示案例-Web-拓展架构-WAF保护-拦截攻击 原理&a…

指针(上)

目录 内存和地址 指针变量和地址 取地址&#xff08;&&#xff09; 解引用&#xff08;*&#xff09; 大小 类型 意义 const修饰 修饰变量 修饰指针 指针运算 指针- 整数 指针-指针 指针的关系运算 野指针 概念 成因 避免 assert断言 指针的使用 strl…

警惕开源信息成为泄密源头

文章目录 前言一、信息公开需谨慎1、警惕采购招标泄密。2、警惕信息公开泄密。3、警惕社交媒体泄密。 二、泄密风险需严防1、健全制度&#xff0c;明确责任。2、加强管控&#xff0c;严格审查。3、提高意识&#xff0c;谨言慎行。 前言 大数据时代&#xff0c;信息在网络空间发…

LearnOpenGL学习(光照 -- 颜色,基础光照,材质,光照贴图)

光照 glm::vec3 lightColor(0.0f, 1.0f, 0.0f); glm::vec3 toyColor(1.0f, 0.5f, 0.31f); glm::vec3 result lightColor * toyColor; // (0.0f, 0.5f, 0.0f); 说明&#xff1a;当我们把光源的颜色与物体的颜色值相乘&#xff0c;所得到的就是这个物体所反射的颜色。 创建…

面向对象(二)——类和对象(上)

1 类的定义 做了关于对象的很多介绍&#xff0c;终于进入代码编写阶段。 本节中重点介绍类和对象的基本定义&#xff0c;属性和方法的基本使用方式。 【示例】类的定义方式 // 每一个源文件必须有且只有一个public class&#xff0c;并且类名和文件名保持一致&#xff01; …

3GPP R18 LTM(L1/L2 Triggered Mobility)是什么鬼?(三) RACH-less LTM cell switch

这篇看下RACH-less LTM cell switch。 相比于RACH-based LTM,RACH-less LTM在进行LTM cell switch之前就要先知道target cell的TA信息,进而才能进行RACH-less过程,这里一般可以通过UE自行测量或者通过RA过程获取,而这里的RA一般是通过PDCCH order过程触发。根据38.300中的描…

实验13 使用预训练resnet18实现CIFAR-10分类

1.数据预处理 首先利用函数transforms.Compose定义了一个预处理函数transform&#xff0c;里面定义了两种操作&#xff0c;一个是将图像转换为Tensor&#xff0c;一个是对图像进行标准化。然后利用函数torchvision.datasets.CIFAR10下载数据集&#xff0c;这个函数有四个常见的…

P1226 快速幂

【STUACM-算法入门-快速幂】https://www.bilibili.com/video/BV1Hi4y1L7qB?p2&vd_sourcee583d26dc0028b3e6ea220aadf5bc7fe 想先把a的b次方算出来再对p取模是不可能的&#xff0c;因为肯定超出long long 范围。 需要知道&#xff1a;(x*y)mod p (x mod p)*(y mod p) mo…

【力扣热题100】—— Day3.反转链表

你不会永远顺遂&#xff0c;更不会一直年轻&#xff0c;你太安静了&#xff0c;是时候出发了 —— 24.12.2 206. 反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&…

containerd安装

containerd安装 参考资料前置准备Installing containerdInstalling runcInstalling CNI plugins containerd is available as a daemon for Linux and Windows. It manages the complete container lifecycle of its host system, from image transfer and storage to containe…

底部导航栏新增功能按键

场景需求&#xff1a; 在底部导航栏添加power案件&#xff0c;单击息屏&#xff0c;长按 关机 如下实现图 借此需求&#xff0c;需要掌握技能&#xff1a; 底部导航栏如何实现新增、修改、删除底部导航栏流程对底部导航栏部分样式如何修改。 比如放不下、顺序排列、坑点如…

Python 入门教程(2)搭建环境 | 2.4、VSCode配置Node.js运行环境

文章目录 一、VSCode配置Node.js运行环境1、软件安装2、安装Node.js插件3、配置VSCode4、创建并运行Node.js文件5、调试Node.js代码 一、VSCode配置Node.js运行环境 1、软件安装 安装下面的软件&#xff1a; 安装Node.js&#xff1a;Node.js官网 下载Node.js安装包。建议选择L…

火语言RPA流程组件介绍--键盘按键

&#x1f6a9;【组件功能】&#xff1a;模拟键盘按键 配置预览 配置说明 按键 点击后,在弹出的软键盘上选择需要的按键 执行后等待时间(ms) 默认值300,执行该组件后等待300毫秒后执行下一个组件. 输入输出 输入类型 万能对象类型(System.Object)输出类型 万能对象类型…

【人工智能-基础】SVM中的核函数到底是什么

文章目录 支持向量机(SVM)中的核函数详解1. 什么是核函数?核函数的作用:2. 核技巧:从低维到高维的映射3. 常见的核函数类型3.1 线性核函数3.2 多项式核函数3.3 高斯径向基函数(RBF核)4. 总结支持向量机(SVM)中的核函数详解 支持向量机(SVM,Support Vector Machine)…

万字长文解读深度学习——多模态模型BLIP2

&#x1f33a;历史文章列表&#x1f33a; 深度学习——优化算法、激活函数、归一化、正则化 深度学习——权重初始化、评估指标、梯度消失和梯度爆炸 深度学习——前向传播与反向传播、神经网络&#xff08;前馈神经网络与反馈神经网络&#xff09;、常见算法概要汇总 万字长…

大数据开发治理--大数据AI公共数据集分析

本文以分析公共数据集的数据示例&#xff0c;为您展示如何使用DataWorks进行简单数据分析工作。本教程以申请免费资源为例为您展示详细操作步骤&#xff0c;您也可以使用付费资源&#xff0c;操作类似。 教程简介 阿里云DataWorks基于多种大数据引擎&#xff0c;为数据仓库、…

ESP32-S3模组上跑通ES8388(13)

接前一篇文章&#xff1a;ESP32-S3模组上跑通ES8388&#xff08;12&#xff09; 二、利用ESP-ADF操作ES8388 2. 详细解析 上一回解析了es8388_init函数中的第6段代码&#xff0c;本回继续往下解析。为了便于理解和回顾&#xff0c;再次贴出es8388_init函数源码&#xff0c;在…

【Mac】安装Gradle

1、说明 Gradle 运行依赖 JVM&#xff0c;需要先安装JDK&#xff0c;Gradle 与 JDK的版本对应参见&#xff1a;Java Compatibility IDEA的版本也是有要求Gradle版本的&#xff0c;二者版本对应关系参见&#xff1a;Third-Party Software and Licenses 本次 Gradle 安装版本为…

根据YAML文件创建Conda环境

YAML&#xff08;全称为YAML Ain’t Markup Language&#xff09;是一种轻量级的标记语言。在Python中&#xff0c;YAML文件包含conda环境名和依赖&#xff0c;如图所示。 根据yaml文件创建Conda环境 1.切换路径 找到miniAnaconda或Anaconda&#xff0c;打开Anaconda Powersh…