spring-cache框架使用笔记

news2025/1/17 23:15:38

spring-cache框架使用笔记

什么是spring-cache框架

spring-cache是spring框架中的一个缓存抽象层,
它提供了一种简便的方式来集成不同的底层缓存实现,
如内存缓存(concurrentMap/ehcache/caffeine)/分布式缓存(redis/couchbase)等
它简化了在app中使用缓存的逻辑,并提供了一组注解和API来实现缓存功能

springCache的特点和功能

1.声明性缓存
spring-cache通过注解的方式,允许开发者在方法级别上声明方法的结果要被缓存。
相关注解有@Cacheable 读取缓存+不存在则缓存
@CacheEvict 清除缓存
@CachePut 强制缓存
@Caching 复合功能注解==(@Cacheable+@CacheEvict+@CachePut)
2.缓存的透明性
spring-cache提供了一致的编程接口,
无论底层使用哪种缓存技术,开发者都可以使用相同的方式访问和管理缓存。
这可以使app轻松切换/替换不同的缓存实现技术,而无需更改业务代码

3.注解定义缓存策略
可以使用注解@Cacheable/@CacheEvict/@CachePut 声明缓存的行为和策略
如声明缓存名称,缓存key
@Cacheable(cacheNames = "user", key = "#id")
会按照key=user::id缓存数据 (可以参见spring-cache-redis缓存效果)

4.支持SpEL表达式
使用SpEL表达式,可以定义缓存的键、条件等。
这允许开发者根据方法参数、方法返回值等动态生成缓存键或决定是否应用缓存。
@Cacheable(cacheNames = "user", key = "#id",condition = "#id != null ")
    public UserDO getById(Long id) {
        returnuserRepo.findById(id).orElse(null);
    }
这个案例只有当id不为空时,才进行缓存
condition属性可以设置缓存的条件,如
#id >=100
#userInfo.id >10
#id%2!=0
等等,必须确保condition能正确返回布尔值,才能决定当前方法最终是否进行缓存

springCache+caffeine配合使用

什么是caffeine

caffeine是一种java内存缓存技术,支持多种缓存策略,
caffeine可以单独使用于普通java项目/springboot/springcloud项目,
这里引入caffeine来作为spring-cache存取缓存的数据区。

xml依赖配置

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>2.8.0</version>
        </dependency>

yml配置

需要在application.yml配置spring-cache使用caffeine

spring:
  cache:
    type: caffeine #设置spring-cache框架使用caffeine存取数据  

caffeine配置类

package cn.test.cache;

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@EnableCaching
@Configuration
public class CacheCfg {
    @Bean
    public CacheManager cacheManager(){
        //定义要缓存的caccheName有哪些
        CaffeineCacheManager caffeineCacheManager =
                new CaffeineCacheManager("user");
        //设置缓存配置
        caffeineCacheManager.setCaffeine(Caffeine.newBuilder()
                //初始容量10
                .initialCapacity(10)
                //最大容量200
                .maximumSize(200)
                //写入过期时间30s
                .expireAfterWrite(30, TimeUnit.SECONDS));
        return caffeineCacheManager;
    }
}

业务代码使用spring-cache相关注解

/**
     * @Cacheable注解标记一个方法时,spring会在执行方法之前,先检查缓存中是否已存在该方法的返回结果
     * 如果存在,则直接返回缓存的结果,不执行方法的实际逻辑
     * 如果不存在,则执行方法并将结果保存到缓存中
     */
    @Cacheable(cacheNames = "user", key = "#id")
    public UserDO getById(Long id) {
        return userRepo.findById(id).orElse(null);
    }

    /**
     * @CacheEvict注解标记一个方法时,spring会在方法执行成功后,
     * 清空指定的缓存项,以确保下次访问时可以重新计算或查询最新的结果
     */
    @CacheEvict(cacheNames = "user", key = "#id")
    public void delUser(Long id) {
        UserDO userDO = userRepo.findById(id).orElse(null);
        if (userDO != null) {
            userRepo.delete(userDO);
        }
    }

    /**
     * @CachePut注解标记一个方法时,spring会在方法执行后,
     * 将返回值放入指定的缓存中,
     * 以便将来的访问可以直接从缓存中获取结果,而不需要再执行方法的实际逻辑
     *
     * @CachePut注解,适用于 创建新缓存 或 强制更新缓存 操作
     */
    @CachePut(cacheNames = "user", key = "#userInfo.id")
    public UserDO addUser(UserDO userInfo) {
        return userRepo.save(userInfo);
    }

    /**
     * 执行updateUserInfo方法时,这里会按key 强制更新caffeine缓存
     */
    @CachePut(cacheNames = "user", key = "#userInfo.id")
    public UserDO updateUserInfo(UserDO userInfo) {
        UserDO userDO = userRepo.findById(userInfo.getId()).orElse(null);
        if (userDO != null) {
            BeanUtils.copyProperties(userInfo,userDO);
            userRepo.save(userDO);
        }
        return userDO;
    }

springCache+redis配合使用

什么是redis

redis是一种分布式缓存技术,不限语言,C/S架构,支持可视化观测,
redis可以单独使用于普通java项目/springboot/springcloud项目/其他语言项目等,
这里引入redis来作为spring-cache框架存取缓存的数据区。

xml依赖配置

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
 <dependency>
     <groupId>org.apache.commons</groupId>
     <artifactId>commons-pool2</artifactId>
     <version>2.5.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

yml配置

spring:
  redis:
    # ip
    host: localhost
    # 端口6379
    port: 6379
    #密码,没有密码则不配置这一项
    password:
    #指定使用redis 16个库中的哪一个,不配置的话,默认配置为0
    database: 2
    lettuce:
      pool:
        min-idle: 0   #连接池最新空闲时间
        max-wait: -1ms  #最大等待时间
        max-active: 8   #最大活跃时间
        max-idle: 8    #最大空闲时间
      shutdown-timeout: 100ms  #连接池关闭超时时间
    timeout: 1000ms  #redis连接超时时间
  cache:
    type: redis     #设置spring-cache框架使用redis存取数据  

redis配置类

package cn.test.cache;

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@EnableCaching
@Configuration
public class RedisConfig {

    /**
     * 设置RedisTemplate使用的序列化器,
     * 这里使用string作为key的序列化,使用jackson作为value的序列化
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();
        RedisSerializer<Object> jsonSerializer = new GenericJackson2JsonRedisSerializer();

        template.setKeySerializer(stringRedisSerializer);
        template.setValueSerializer(jsonSerializer);

        template.setHashKeySerializer(stringRedisSerializer);
        template.setHashValueSerializer(jsonSerializer);
        return template;
    }


    /**
     * 设置spring-cache使用redis后,要配置cacheManager缓存管理器
     *
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();
        RedisSerializer<Object> jsonSerializer = new GenericJackson2JsonRedisSerializer();
        RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration
                .defaultCacheConfig()
                //设置spring-cache缓存到redis的数据有效期是60s
                .entryTtl(Duration.ofSeconds(60))
                //key的序列化使用字符串
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
                //value的序列化使用jackson
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonSerializer));

        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(cacheConfiguration)
                .build();
    }

}

业务代码使用spring-cache相关注解

 @Cacheable(cacheNames = "user", key = "#id")
    public UserDO getById(Long id) {
        return userRepo.findById(id).orElse(null);
    }

    @CacheEvict(cacheNames = "user", key = "#id")
    public void delUser(Long id) {
        UserDO userDO = userRepo.findById(id).orElse(null);
        if (userDO != null) {
            userRepo.delete(userDO);
        }
    }

    @CachePut(cacheNames = "user", key = "#userInfo.id")
    public UserDO addUser(UserDO userInfo) {
        return userRepo.save(userInfo);
    }

    @CachePut(cacheNames = "user", key = "#userInfo.id")
    public UserDO updateUserInfo(UserDO userInfo) {
        UserDO userDO = userRepo.findById(userInfo.getId()).orElse(null);
        if (userDO != null) {
            BeanUtils.copyProperties(userInfo,userDO);
            userRepo.save(userDO);
        }
        return userDO;
    }

使用RDM工具观察redis存储的数据

因为RedisCacheManager配置了使用jackson序列化,这里缓存数据值是以json格式存储到redis的。

可以观察到spring-cache存入redis的缓存有效期是60s (因为RedisCacheManager配置了60秒);

缓存的key是

user::1

缓存的value是

{
  "@class": "cn.test.orm.user.UserDO",
  "id": 1,
  "account": "ewr3",
  "pwd": "23r3r",
  "remark": "23r3r",
  "createTime": [
    "java.sql.Timestamp",
    "2023-08-02 11:14:02"
  ],
  "updateTime": [
    "java.sql.Timestamp",
    "2023-08-02 11:14:02"
  ],
  "isDel": 0
}

在这里插入图片描述

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

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

相关文章

网络安全进阶学习第十课——MySQL手工注入

文章目录 一、MYSQL数据库常用函数二、MYSQL默认的4个系统数据库以及重点库和表三、判断数据库类型四、联合查询注入1、具体步骤&#xff08;靶场演示&#xff09;&#xff1a;1&#xff09;首先判断注入点2&#xff09;判断是数字型还是字符型3&#xff09;要判断注入点的列数…

O3DE的Pass

Pass介绍 Pass是具有输入和输出的渲染过程。 在最终渲染帧中看到的每个细节都是通过一系列Pass&#xff08;前一个Pass的输出是下一个Pass的输入&#xff09;计算出来的。Pass可以生成图像&#xff08;作为纹理、缓冲区或渲染目标&#xff09;。每个图像都包含关于场景的特定…

【话题】感觉和身边其他人有差距怎么办?也许自我调整很重要

每个人能力有限&#xff0c;水平高低不同&#xff0c;我们身在大环境里&#xff0c;虽然在同一个起跑线上&#xff0c;但是时间久了&#xff0c;你会发现&#xff0c;并越来越感觉到和身边其他人有了差距&#xff0c;慢慢的会有一定的落差感&#xff0c;怎么办呢&#xff01;通…

Android手机信息获取(详细版)

经典好文推荐,通过阅读本文,您将收获以下知识点: 一、 获取手机基本信息(厂商、型号等参数) 二、设备信息获取实现图 三、 获取手机设备 宽、高、IMEI 信息 四、 获取手机厂商名、产品名、手机品牌、手机型号、主板名、设备名 五、获取手机硬件名、SDK版本、android版本 、语…

无代码开发:打破传统开发模式,引领数字化转型新方向

随着数字化转型的加速&#xff0c;企业对于高效、便捷的软件开发需求愈发旺盛。无代码开发作为一种新兴的软件开发模式&#xff0c;以其可视化、模块化的开发方式&#xff0c;为数字化转型提供了新的方向。本文将从无代码开发的优势、应用场景、如何实现等方面进行详细解读&…

中介者模式——协调多个对象之间的交互

1、简介 1.1、概述 如果在一个系统中对象之间的联系呈现为网状结构&#xff0c;如下图所示&#xff1a; 对象之间存在大量的多对多联系&#xff0c;将导致系统非常复杂&#xff0c;这些对象既会影响别的对象&#xff0c;也会被别的对象所影响&#xff0c;这些对象称为同事对…

配置root账户ssh免密登录并使用docker-machine构建docker服务

简介 Docker Machine是一种可以在多种平台上快速安装和维护docker运行环境&#xff0c;并支持多种平台&#xff0c;让用户可以在很短时间内在本地或云环境中搭建一套docker主机集群的工具。 使用docker-machine命令&#xff0c;可以启动、审查、停止、重启托管的docker 也可以…

揭示用户激活的价值:为什么产品经理应该关注

如果你在一家SaaS公司工作&#xff0c;你可能自诩对漏斗指标有很好的理解&#xff0c;你可能可以倒背如流——获取&#xff0c;用户激活&#xff0c;保留&#xff0c;推荐和收入。你甚至可能记得它们的出处&#xff0c;但是你对这些指标的理解到底有多深呢&#xff1f;你知道你…

node.js系列-多种方案教你在node程序中同时使用CommonJS 和 ES Module 混合开发最佳实践

前情提要 我们平时使用的npm 第三方包一般基于这两种规范开发的&#xff0c;很容易遇到一个项目里既有 CommonJS 又有 ES Module 的情况&#xff0c;那么我们应该如何解决这种CommonJS 和 ES Module 混合开发的问题呢&#xff1f; CommonJS是什么&#xff1f; 2009年&#x…

C++学习笔记总结练习--容器

容器 1 简介 新标准库的容器壁使用原始的数组实现的数据结构要快很多。经过了精心的优化。 确定使用哪种容器 除非有明确的理由&#xff0c;否则使用vector随机元素访问vector或deque容器中间插入或者插入元素list、forward_list头尾插入元素&#xff0c;使用deque可以在输入…

RelativeSource有四种类型

Self FindAncestor TemplatedParent PreviousData a.Self Self用于绑定源和绑定目标相同的场景中。对象的一个属性与同一对象的另一个属性绑定。 例如&#xff0c;让我们取一个高度和宽度相同的椭圆。在XAML文件中添加下面给出的代码。宽度属性与高度属性相对绑定。 <G…

Stephen Wolfram:“足够大的网络肯定能做任何事!”

“Surely a Network That’s Big Enough Can Do Anything!” “足够大的网络肯定能做任何事&#xff01;” The capabilities of something like ChatGPT seem so impressive that one might imagine that if one could just “keep going” and train larger and larger neura…

【Kubernetes】Kubernetes的部署

kubernetes 一、Kubernetes 的安装部署1. 常见的安装部署方式1.1 Minikube1.2 Kubeadm1.3 二进制安装部署 2. K8S 部署 二进制与高可用的区别2.1 二进制部署2.2 kubeadm 部署 二、Kubernetes 的部署过程1. 二进制部署1.1 服务器相关设置以及架构1.2 操作系统初始化配置1.3 部署…

【前端|Javascript第1篇】一文搞懂Javascript的基本语法

欢迎来到JavaScript的奇妙世界&#xff01;作为前端开发的基石&#xff0c;JavaScript为网页增色不少&#xff0c;赋予了静态页面活力与交互性。如果你是一名前端小白&#xff0c;对编程一无所知&#xff0c;或者只是听说过JavaScript却从未涉足过&#xff0c;那么你来对了地方…

《探索文心千帆大模型平台: 代码编写从此变得轻松》

文章目录 前言一、初识文心千帆1.1 功能丰富1.2 注册登录 二、内置第三方大模型2.1 ERNIE-Bot模型2.2 ERNIE-Bot-turbo模型2.3 BLOOMZ-7B模型2.4 Llama模型全家桶2.5 在线体验2.5.1 代码编写能力简单提问复杂提问报错解决添加注释 2.5.2 逻辑判断先有鸡还是先有蛋&#xff1f;鸡…

CTF-MISC:BUUCTF练习汇总(26-31题)

CTF-MISC&#xff1a;BUUCTF练习汇总 26、后门查杀27、webshell后门28、来首歌吧29、荷兰宽带数据泄露30、面具下的flag31、九连环 26、后门查杀 解题思路&#xff1a;题干可知webshell的密码为flag&#xff0c;且下载的文件为网站源码&#xff0c;人工查找不太现实&#xff0…

【框架篇】Spring MVC 介绍及使用(详细教程)

Spring MVC 介绍 1&#xff0c;MVC 设计模式 MVC&#xff08;Model-View-Controller&#xff09;是一种常见的软件设计模式&#xff0c;用于将应用程序的逻辑分离成三个独立的组件&#xff1a; 模型&#xff08;Model&#xff09;&#xff1a;模型是应用程序的数据和业务逻辑…

微信小程序iconfont真机渲染失败

解决方法&#xff1a; 1.将下载的.woff文件在transfonter转为base64&#xff0c; 2.打开网站&#xff0c;导入文件&#xff0c;开启base64按钮&#xff0c;下载转换后的文件 3. 在下载解压后的文件夹中找到stylesheet.css&#xff0c;并复制其中的base64 4. 修改index.wxss文…

proj库配置与使用(window11,vs2019,x64)

前置安装依赖 1.SQLite3 安装 亲测 (97条消息) SQLite3源码下载与编译&#xff08;开发环境&#xff1a;Win10VS2022&#xff09;_sqlite3 下载_林夕07的博客-CSDN博客 2.TIFF 亲测 (97条消息) Win11下基于cmake-3.26.3 完美编译 TIFF-4.5.0源码_tiff 编译_GIS子枫的博客-C…