什么是Spring Cache?Spring项目如何使用?

news2024/10/2 6:41:42

前言

目前Spring Cloud微服务在Web项目中占据了主流地位,如果去面试关于Spring Cloud的岗位时,面试官一般都会提问你的项目是如何优化的,从哪些方面入手去优化。而缓存技术绝对是项目必不可少的,所以我们必须掌握好Java项目的缓存技术。

目前,在 Java 中,常见的缓存有以下几种:

  1. JVM 缓存:JVM 缓存是指 Java 虚拟机为类加载器所创建的缓存。Java 虚拟机通过缓存已经加载的类来提高应用程序的性能。
  2. 数据库缓存:数据库缓存是指将查询结果缓存在内存中,以便下次查询时可以直接从内存中获取,避免了重复查询数据库的操作。
  3. Web 缓存:Web 缓存是指将 Web 页面、图片等静态资源缓存到本地,以便下次访问时可以直接从本地获取,提高 Web 应用程序的性能。
  4. 分布式缓存:分布式缓存是指将数据缓存到多个节点上,以便多个应用程序可以共享缓存,提高系统的性能和可伸缩性。
  5. 本地缓存:本地缓存是指将数据存储在应用程序本地的内存或磁盘上,以便快速读取和更新数据,避免了频繁访问远程资源的开销。
  6. Spring 缓存:Spring 框架提供了一套缓存框架,可以将方法调用的结果缓存到内存或磁盘中,以便下次调用时可以直接从缓存中获取结果,提高应用程序的性能。

今天我主要讲解Spring 缓存,因为Spring cache简单、方便、效率高,绝对是Spring Cloud微服务项目的最佳选择

一、什么是Spring Cache

Spring Cache是Spring框架中的一个模块,它提供了一种简单的方法来缓存数据和对象。通过使用Spring Cache,开发人员可以将常用的数据和对象存储在内存中,以提高应用程序的性能和响应速度。

Spring Cache支持多种缓存实现,包括内存、Redis、Memcached等。开发人员可以根据自己的需求选择合适的缓存实现。

Spring Cache还提供了一些高级功能,如缓存预热、缓存过期、分布式缓存等,使得开发人员可以更加灵活地使用缓存。同时,Spring Cache还与Spring框架的其他模块集成良好,可以方便地与其他组件一起使用。

1、优点

  • 提高性能:通过将常用的数据和对象存储在内存中,Spring Cache可以大大提高应用程序的性能和响应速度。

  • 简化代码:Spring Cache提供了一些高级功能,如缓存预热、缓存过期和分布式缓存等,使得开发人员可以更加灵活地使用缓存,从而简化了代码。

  • 促进团队协作:Spring Cache可以促进团队协作,因为它可以在多个开发人员之间共享缓存数据,从而减少了重复的工作和代码冗余。

  • 实现分布式系统:Spring Cache可以与Spring框架的其他模块集成良好,可以方便地与其他组件一起使用,从而实现分布式系统。

  • 支持多种缓存实现:Spring Cache支持多种缓存实现,包括内存、Redis、Memcached等,开发人员可以根据自己的需求选择合适的缓存实现。

  • 提供基本的Cache抽象:方便切换各种底层Cache,通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成。

  • 提供事务回滚时也自动回滚缓存:支持比较复杂的缓存逻辑。

  • 通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成。

2、缺点

在使用 Spring Cache 时,可能会遇到一些不足之处。下面是一些可能的不足:

  • 读模式下缓存失效的问题:在 Spring Cache 中,缓存的读模式下可能会出现缓存失效的问题。这是因为在读模式下,缓存的数据可能会过期,导致缓存失效。为了解决这个问题,可以使用 Spring Cache 提供的读写分离功能,将读请求和写请求分别发送到不同的 Cache 实例。
  • 缓存穿透:在某些情况下,缓存穿透可能会发生。这是因为在读模式下,缓存的数据可能会被其他组件重新读取,导致缓存穿透。为了避免缓存穿透,可以使用 Spring Cache 提供的写模式,并设置 cache-null-values: true 来允许写入空值。
  • 缓存击穿:在大量并发请求的情况下,可能会出现缓存击穿的问题。这是因为在这种情况下,同时有大量的请求查询一个正好过期的数据,导致请求全部转发到数据库,从而导致数据库压力过大。为了避免缓存击穿,可以设置缓存的过期时间,或者使用其它缓存框架,如 Ehcache 或 RedisCache。
  • 缓存雪崩:在某些情况下,缓存的大量键过期时间相同,导致某一刻缓存同时失效,请求全部转发到数据库。为了避免缓存雪崩,可以使用 Spring Cache 提供的键值哈希策略,将键值哈希到不同的桶中,避免键值过期时间相同的问题。
  • 总的来说,Spring Cache 在处理读模式下缓存失效、缓存穿透、缓存击穿和缓存雪崩等问题方面表现良好,但在写模式下需要使用其他方式进行处理。使用 Spring Cache 可以轻松地管理和优化应用程序的缓存。

二、Spring Cache原理

1、基本流程图

在这里插入图片描述

2、原理

当我们在Spring中使用缓存时,会按照以下步骤进行操作:

  • 首先,Spring会检查是否使用了缓存注解。如果使用了,那么会在缓存的缓存管理器中查找是否有已经缓存的数据。

  • 如果缓存管理器中没有对应的缓存数据,那么会执行方法体中的代码,并将结果缓存起来。

  • 如果缓存管理器中已经存在缓存数据,那么直接返回缓存数据。

当我们在更新数据时,会按照以下步骤进行操作:

  • 首先,更新方法会执行,然后会更新数据库中的数据。

  • 然后,Spring会在缓存管理器中查找是否存在已经缓存的数据。

  • 如果存在缓存数据,那么会将缓存数据删除。

  • 下一次查询时,会重新执行方法体中的代码,并将新的结果缓存起来。

以上就是Spring Cache的工作原理。

三、Spring Cache具体实现与应用

1、引入SpringCache依赖

  • .引入SpringCache依赖
<!--Spring Cache,使用注解简化开发-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

-.引入redis依赖

<!--redis启动器-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、属性配置

spring:
  redis:
    host: 192.168.56.10
    port: 6379
  cache:
    type: redis # 使用redis作为缓存
    redis:
      time-to-live: 3600s # 过期时间
      # key-prefix: CACHE_ # 会导致自己在@Cacheable里设置的名字失效,所以这里不指定
      use-key-prefix: true # key值加前缀
      cache-null-values: true # 缓存控制

3、类配置

@EnableConfigurationProperties(CacheProperties.class)
@EnableCaching
@Configuration
public class MyCacheConfig {

//    @Autowired
//    CacheProperties cacheProperties;

    /**
     * 需要将配置文件中的配置设置上
     * 1、使配置类生效
     * 1)开启配置类与属性绑定功能EnableConfigurationProperties
     *
     * @ConfigurationProperties(prefix = "spring.cache")  public class CacheProperties
     * 2)注入就可以使用了
     * @Autowired CacheProperties cacheProperties;
     * 3)直接在方法参数上加入属性参数redisCacheConfiguration(CacheProperties redisProperties)
     * 自动从IOC容器中找
     * <p>
     * 2、给config设置上
     */
    @Bean
    RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();

        //序列化key,不变
        config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        //序列化值,使用json
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        // 当自己往IOC注入了RedisCacheConfiguration配置类时,以下参数全都失效,需要手动设置
        CacheProperties.Redis redisProperties = cacheProperties.getRedis();
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
        }
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }
        return config;
    }
}

4、查询时读取缓存

 @Cacheable(value = {"category"}, key = "#root.method.name", sync = true)
    @Override
    public List<CategoryEntity> getLevel1Categorys() {
        System.out.println("调用了getLevel1Categorys...");
        // 查询父id=0
        return baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0));
    }

5、更新时读取缓存

@CacheEvict(value = {"category"}, allEntries = true) //删除category分区里所有的缓存
    @Transactional
    @Override
    public void updateCascade(CategoryEntity category) {
        this.updateById(category);
        if (!StringUtils.isEmpty(category.getName())) {
            // 更新冗余表
            categoryBrandRelationService.updateCategory(category.getCatId(), category.getName());
            // TODO 更新其他冗余表
        }       
    }

6、双写模式

/**
 * 级联更新
 * 缓存策略:双写模式,方法执行完更新缓存
 */
@CachePut(value = "category", key = "'level1Categorys'")
@Transactional
@Override
public void updateCascade(CategoryEntity category) {
    this.updateById(category);
    if (!StringUtils.isEmpty(category.getName())) {
        // 更新冗余表
        categoryBrandRelationService.updateCategory(category.getCatId(), category.getName());
        // TODO 更新其他冗余表
    }
}

7、注解解释:

@Cacheable:更新缓存【读操作:如果当前缓存存在方法不被执行,不存在则执行get方法并更新缓存】
@CacheEvict:删除缓存【写操作:失效模式,方法执行完删除缓存】
@CachePut:更新缓存【写操作:双写模式,方法执行完更新缓存】
@Caching:组合以上多个缓存操作
@CacheConfig:在类级别共享缓存的相同配置

源码下载:
gitee.com/charlinchenlin/koo-erp

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

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

相关文章

unity 3种办法实现血条效果并实现3d世界血条一直看向摄像机

普通血条栏: 渐变色血条栏: 缓冲血条栏: 3D场景血条栏跟随玩家移动: 普通血条栏: 在Canvas下创建一个空物体HP bar,在空物体下方创建3个Image,分别为血条框bar 黑色,最大HP maxHP 白色,和当前HP currentHP 红色。(PS:注意先后顺序以调整显示的图层) 效果: …

java中排序

1.传统比较器格式 2.stream 3.结果 4.源码 List<String> list Arrays.asList("201305", "200305", "199009", "200208");Collections.sort(list, new Comparator<String>() {Overridepublic int compare(String o1, Stri…

SpringMVC 万字通关

文章目录 1. 什么是 Spring MVC?1.1 MVC 定义1.2 MVC 和 Spring MVC 的关系 2. Spring MVC 有什么用 ?3. 如何学 Spring MVC ?3.1 Spring MVC 的创建3.2 实现连接功能3.2.1 RquestMapping 详解1. RequestMapping 支持什么请求?2. 请求限定3. GetMapping 和 PostMapping4. c…

Sharding-Sphere系列-主从配置和分库分表

主从配置和分库分表 Sharding-Sphere组成 Sharding-JDBC Sharding-Proxy Sharding-Sidecar&#xff08;TODO&#xff09; Sharding-JDBC表的概念 逻辑表 广播表 绑定表 Sharding-JDBC中的分片策略 自动分片算法 标准分片算法 复合分片算法 自定义分片算法 分布式…

Mybatis-Plus 自动属性填充与自定义Insert into语句顺序

前言&#xff1a;系统中使用了Mybatis-Plus 自动属性填充为实体统一进行属性的填值&#xff0c;在Mapper的xml 文件中 insert into 语句 使用 <if test"id ! null">id,</if> 进行判断会发现该属性是空的&#xff0c;明明已经为改字段进行了属性的自动填充…

百度2023年Q1财报解析:AI+生态战略加速助推

原创 | 文 BFT机器人 01 百度靠AI实现翻身 &#xff08;一&#xff09;盈利能力 百度凭借着强大的AI能力&#xff0c;成功地实现了从依赖搜索业务的互联网公司到AI公司的转型。 从盈利能力层面上看&#xff0c;在第一季度&#xff0c;百度实现了营收311.44亿元&#xff0c;同比…

unity愤怒的小鸟学习制作(二)

终于又开始了啦啦啦&#xff0c;我有一个自己的相机了&#xff0c;真开心&#xff0c;诶嘿 视频链接和素材如下&#xff1a;视频 小鸟的飞出 想要让小鸟在拉开弹弓之后能飞出去&#xff0c;就必须让这个组件失活&#xff0c;如下 所以我们更改脚本内容&#xff0c;加入&#…

HarmonyOS应用端云一体化开发主要流程

图示 主要步骤 序号 阶段 任务 说明 1 创建端云一体化开发工程 选择工程类型与云开发模板 确定工程类型&#xff1a;选择“Application”或“Atomic Service”页签&#xff0c;确定创建的是HarmonyOS应用工程还是原子化服务工程。选择云开发模板&#xff0c;包括通用云开…

【FMC202】基于FMC标准的1路CameraLink Full 输入、1路DVI输出 子卡模块

产品概述 FMC202是一款基于FMC接口标准的1路CameraLink Full模式&#xff08;或者2路CameraLink Base模式&#xff09;采集、1路HDMI&#xff08;DVI&#xff09;视频输出的子卡模块&#xff0c;该模块具有2个CameraLink端口&#xff08;SDR&#xff0c;26PIN&#xff09;&…

Docker部署apache superset

使用Docker compose在docker中部署Apache Superset 说明&#xff1a;部署步骤按照superset官网说明总结而来-2023年 1、第一步安装docker 、docker compose。 这里我选择手动下载rpm包&#xff0c;然后yum install *.rpm方式来安装。 下载地址&#xff1a;https://download.…

MADDPG-学习笔记(2)

注意&#xff1a;进行本文的实验前&#xff0c;为了加快训练速度&#xff0c;进行了参数调整 num-episodes&#xff1a;由60000改成了10000 lr:由0.01改成了0.1 batch-size:由1024改成了32 1.报错 1.1 AttributeError: Scenario object has no attribute benchmark_data …

ApiKit 介绍及基本用法

1、ApiKit介绍及下载 ApiKitAPI 管理 Mock 自动化测试 异常监控 团队协作 结合 API 设计、文档管理、自动化测试、监控、研发管理和团队协作的一站式 API 生产平台&#xff0c;从个人开发者到跨国企业用户&#xff0c;Apikit 帮助全球超过50万开发者和10万家企业更快、更好…

【Flutter】Flutter CLI (2):调试分析项目 flutter analyze 命令详解

文章目录 一、前言二、对现有项目进行分析和调试1. flutter analyze2. 修改代码暴露错误3. 再次执行flutter analyze4. 调试模式运行代码 flutter run三、本文涉及命令的完整说明1.flutter analyze四、总结一、前言 在上一篇文章中,我们对 Flutter CLI 的命令进行了分类,并通…

Array的扩展方法(from、find、findlndex、includes)

Array.from() 构造函数方法:Array.from() 将类数组或可遍历对象转换为真正的数组 示例 <script>// 构造函数方法:Array.from()// 将类数组或可遍历对象转换为真正的数组let arr {0: a,1: b,2: c,length: 3,};let arr1 Array.from(arr);console.log(arr1);//["…

对回溯的理解与思考(从决策树遍历角度分析)

对于回溯的经典问题&#xff0c;就是全排列和各种各样全排列的变体和八皇后问题。 算法框架 对于回溯算法框架。其实解决一个回溯问题&#xff0c;实际上就是一个决策树的遍历过程。 这也就是为什么在刷算法题之前&#xff0c;一定要从树的题目开始刷&#xff0c;后期可以很方…

检索 COM 类工厂中 CLSID 为 {} 的组件失败, 内存资源不足,无法处理此命令

如果您收到ERROR_NOT_ENOUGH_MEMORY消息&#xff0c;提示没有足够的存储空间来处理此命令描述&#xff0c;请按照本文中列出的故障排除步骤进行修复。 此错误代码影响Windows服务器&#xff0c;导致系统崩溃&#xff0c;并在错误日志中显示“没有足够的存储空间来处理此命令”。…

Qt+QtWebApp开发笔记(二):http服务器日志系统介绍、添加日志系统至Demo测试

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/130762721 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

Clickhouse 入门到精通-Clickhouse工作原理

Clickhouse 为什么做查询分析那么快&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f; 因为clickhouse使用了下列方案&#xff1a; clickhouse 数据分区clickhouse 列式存储clickhouse 一级索引&#xff08;主键索引&#…

企业数字转型加速器!居然是他!该不会还有人没用上吧?

随着数字化时代的到来和技术的发展&#xff0c;企业数字化转型已经成为全球企业发展的重要趋势。然而&#xff0c;数字化转型的过程却并非一帆风顺&#xff0c;常常因为 IT 复杂度高、开发周期长等问题而遇到许多挑战&#xff0c;这时候低代码开发平台就能够发挥重要作用。 低代…

我们为什么还要学习Altium Designer?

Altium Designe&#xff08;简称“AD”&#xff09;是电子设计领域中备受推崇的软件工具之一&#xff0c;拥有强大的功能和灵活的设计环境&#xff0c;也是要用最广泛的EDA工具之一&#xff0c;为电子工程师提供了无限可能&#xff0c;但很多工程师学完AD基本操作就转投其他EDA…