基于SpringCache实现数据缓存

SpringCache

SpringCache是一个框架实现了基本注解的缓存功能,只需要简单的添加一个@EnableCaching 注解就能实现缓存功能

  • SpringCache框架只是提供了一层抽象,底层可以切换CacheManager接口的不同实现类即使用不同的缓存技术,默认的实现是ConcurrentMapCacheManager
  • ConcurrentMapCacheManager是基于内存存储数据的,所以重启服务后缓存数据就会消失
CacheManger描述
EhCacheCacheManager使用EhCache作为缓存技术
GuavaCacheManager使用Googke的GuavaCache作为缓存技术
RedisCacheManager使用Rdis作为缓存技术

环境准备

第一步: 定义实体类User且实现序列化接口

@Data
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long id;
    private String name;
    private int age;
    private String address;
}

第二步: 定义Mapper接口

@Mapper
public interface UserMapper extends BaseMapper<User>{
}

第三步: 定义UserService接口及其实现类

public interface UserService extends IService<User> {
    
}

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
    
}

第四步: 定义接口

@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
    // 默认的实现是ConcurrentMapCacheManager
    @Autowired
    private CacheManager cacheManager;
    
    @Autowired
    private UserService userService;
}

第五步: 开启缓存注解功能

@Slf4j
@SpringBootApplication
// 开启缓存注解功能
@EnableCaching
public class CacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheDemoApplication.class,args);
        log.info("项目启动成功...");
    }
}

SpringCache常用注解

因为缓存的数据key一定是唯一的,所以key支持SpEL表达式来动态的计算key(条件判断也支持SpEL表达式)

  • #result: 代表方法的返回值,如#result.id表示获取返回值对象的id属性值作为key
  • #root: 代表整个方法对象,如#root.args[0].id表示获取方法的第一个参数的id属性值作为key
  • #p[i]: 代表方法的参数,如p[0].id表示获取方法的第一个参数的id属性值作为key
  • #方法参数名: 代表方法的参数,如#user.id获取参数user对象的id属性值作为key

condition和unless的区别

  • condition: 表示满足条件才进行缓存,不支持SpEL表达式中的#result
  • unless: 表示满足条件不进行缓存,支持SpEL表达式中的#result
注解说明
@EnableCaching开启缓存注解功能
@Cacheable在方法执行前spring先查看缓存中是否有数据,如果有数据则直接返回缓存数据;若没有数据调用方法并将方法返回值放到缓存中(查询方法)
@CachePut将方法的返回值放到缓存中(适合新增的方法)
@CacheEvict将一条或者多条数据从缓存中删除(适合删除和更新的方法啊)

@CachePut(新增)

@CachePut主要针对方法配置,能够根据方法的请求参数将方法的返回值进行缓存,每次都会触发真实方法的调用

注解说明举例
value指定缓存的名称必须指定至少一个@Cacheable(value=”mycache”)或者@Cacheable(value=(“cache7”, “cache2”]
key指定缓存的key(可以为空),但必须是动态唯一的,表示某类缓存中的一个具体数据@Cacheable(value=”testcache”,key=”#userName”)
condition指定缓存的条件(可以为空)返回true或者false,满足条件才进行缓存@Cacheable(value=”testcache”,condition=”#userName.length()>2”)

测试新增的方法将方法的返回值进行缓存

在这里插入图片描述

@CachePut(value="userCache",key="#user.id")
@PostMapping
public User save(User user){
    userService.save(user);
    return user;
}

查看ConcurrentMapCacheManager中缓存的结果

在这里插入图片描述

@CachEvict(删除)

@CachEvict主要针对方法配置,能够根据一定的条件将缓存中的数据进行清空

注解说明举例
value缓存的名称必须指定且至少一个@Cacheable(value=”mycache”)或者@Cacheable(value={“cache1”, “cache2”]
key指定缓存的key(可以为空),但必须是动态唯一的@Cacheable(value=”testcache”,key=”#userName”)
condition指定缓存的条件(可以为空)返回true或者false,满足条件才进行缓存@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
allEntries是否清空某类缓存下的所有数据,默认为false@CachEvict(value=”testcache”,allEntries=true)
beforelnvocation是否在方法执行前就清空,缺省为false,如果指定为true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存@CachEvict(value=”testcache”, beforelnvocation=true)

测试删除的方法清楚缓存中指定的key

在这里插入图片描述

@CachEvict(value="userCache",key="#user.id")
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id){
    userService.removeById(id);
}

测试更新的方法清楚缓存中指定的key

在这里插入图片描述

@CachEvict(value="userCache",key="#id")
@PutMapping
public User update(User user){
    userService.updateById(user);
    return user;
}

@Cacheable(查询)

@Cacheable注解主要针对方法配置,如果缓存中没有数据能够根据方法的请求参数对方法结果进行缓存,如果缓存中有数据则不会调用方法

  • 如果查询的数据在数据库中也查询不到则会缓存一个null,这样下次再查询这个数据时直接返回null,避免缓存穿透
注解说明举例
value指定缓存的名称表示一类缓存,每个缓存名称下可以存储多个key@Cacheable(value=”mycache”)或者@Cacheable(value=(“cache7”, “cache2”]
key(唯一)指定缓存数据的key(可以为空),表示某类缓存中的一个具体数据@Cacheable(value=”testcache”,key=”#userName”)
condition指定缓存的条件(可以为空)返回true或者false,满足条件才进行缓存@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
unless指定缓存的条件(可以为空)返回true或者false,满足条件不进行缓存@Cacheable(value=”testcache”,unless=”#userName.length()>2”)

测试根据id查询的方法,如果缓存中没有数据则将方法返回值进行缓存,如果缓存中有对应数据则不调用方法直接返回缓存的数据

在这里插入图片描述

@Cacheable(value="userCache",key="#id")
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
    User user = userService.getById(id);
    return user;
}
// 查询结果为null不缓存,condition不支持#result
@Cacheable(value="userCache",key="#id",unless="#result==null")
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
    User user = userService.getById(id);
    return user;
}

测试根据多个条件进行查询的方法,不同的查询条件对应不同的缓存数据

在这里插入图片描述

@Cacheable(value="userCache",key="#user.id+'_'+#user.name")//查询条件和id和name有关
@GetMapping("/list")
public List<User> list(User user){
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(user.getId() != null,User::getId,user.getId());
    queryWrapper.eq(user.getName() != null,User::getName,user.getName());
    List<User> list = userService.list(queryWrapper);
    return list;
}

查询缓存的结果

在这里插入图片描述

使用SpringCache基于redis

使用步骤

第一步: 在SpringBoot项目中使用缓存技术只需要在项目中导入相关缓存技术的依赖包,并在启动类上使用@EnableCaching开启缓存技术支持即可

  • 如果想使用SpringCache的基本功能只需要导入spring-context依赖即可(导入spring-boot-starter-web会自动传递)
<!--使用Redis作为缓存技术,里面包含CacheManager接口的实现类-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--对SpringCache中CacheManager接口的实现类进行了扩展-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

第二步: 在application.yml文件中配置redis相关的配置

spring:
  redis:
    host: 101.XXX.XXX.160 #redis服务所在地址
    password: root
    port: 6379
    database: 0
  cache:
    redis:
      time-to-live: 3600000 #设置缓存有效期为一小时(单位毫秒),如果不设置则一直存活
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
    // 底层实现是RedisCacheManager
    @Autowired
    private CacheManager cacheManager;
    
    @Autowired
    private UserService userService;
}

第三步: 在启动类上加@EnableCaching注解表示开启缓存注解功能

@Slf4j
@SpringBootApplication
// 开启缓存注解功能
@EnableCaching
public class CacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheDemoApplication.class,args);
        log.info("项目启动成功...");
    }
}

第四步: 在Controller的方法上加上@Cacheable,@CachePut,@CacheEvict缓存注解进行缓存操作

在这里插入图片描述

// 查询结果为null不缓存,condition不支持#result
@Cacheable(value="userCache",key="#id",unless="#result==null")
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
    User user = userService.getById(id);
    return user;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中间件 | Kafka - [常见问题]

INDEX 1 为什么快2 消息丢失2.1 消息丢失位置2.2 如何避免消息丢失 3 顺序消费 1 为什么快 kafka使用的是基于文件的顺序存储 代价是只能通过offset标记消费情况并总 partition 数越高&#xff0c;性能越下降&#xff0c;可降低一个数量级 每个 partition 的消息会保存在一个独…

C++day3——类中的成员函数

思维导图&#xff1a; 2、设计一个Per类&#xff0c;类中包含私有成员&#xff1a;姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员&#xff1a;成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 #in…

力扣串题:验证回文串2

bool judge(char *s,int m,int n){while(m<n){if(s[m]!s[n]){return false;}m,n--;}return true; } bool validPalindrome(char * s){for(int i0,jstrlen(s)-1;i<j;i,j--){if(s[i]!s[j]){return (judge(s,i1,j)||judge(s,i,j-1));}}return true; }这个题直接背大佬代码吧…

彩虹外链网盘界面UI美化版超级简洁好看

彩虹外链网盘界面UI美化版 彩虹外链网盘&#xff0c;是一款PHP网盘与外链分享程序&#xff0c;支持所有格式文件的上传&#xff0c;可以生成文件外链、图片外链、音乐视频外链&#xff0c;生成外链同时自动生成相应的UBB代码和HTML代码&#xff0c;还可支持文本、图片、音乐、…

Albumentations——广泛应用于工业界、学术界、AI竞赛和开源项目中的CV数据增强工具

Albumentations: fast and flexible image augmentationsDiscover Albumentations: an open-source library offering efficient and customizable image augmentations to boost machine learning and computer vision model performance.https://albumentations.ai/

HM v.16.22 顺序读源码day1---encmain.cpp

文章目录 encmain.cpp引入的库执行主体1. 读取输入的配置文件2. 编码启动和过程计时 实现细节1. cTAppEncTop.parseCfg( argc, argv )&#xff1b;2. df::program_options_lite::ParseFailure;3. EnvVar::printEnvVar();4. EnvVar::printEnvVarInUse();5. printMacroSettings()…

plt保存PDF矢量文件中嵌入可编辑字体(可illustrator编辑)

背景&#xff1a; 用默认 plt.savefig() 保存图片&#xff0c;图中文字是以瞄点保存&#xff0c;而不是以文字格式。在编辑矢量图中&#xff0c;无法调整文字大小和字体。 方法&#xff1a; import matplotlib.pyplot as plt import numpy as np# ------输出的图片为illustr…

RabbitMQ备份交换机与优先级队列

1. 备份交换机 备份交换机可以理解为 RabbitMQ 中交换机的“备胎”&#xff0c;当我们为某一个交换机声明一个对应的备份交换机时&#xff0c;就是为它创建一个备胎&#xff0c;当交换机接收到一条不可路由消息时&#xff0c;将会把这条消息转发到备份交换机中&#xff0c;由备…

数据仓库的基本概念、基本特征、体系结构

个人看书学习心得及日常复习思考记录&#xff0c;个人随笔。 数据仓库的基本概念、基本特征 数据仓库的定义&#xff1a;数据仓库是一个面向主题的、集成的、不可更新的、随时间不断变化的数据集合&#xff0c;用以更好地支持企业或组织的决策分析处理。 数据仓库中数据的4个…

26-Java访问者模式 ( Visitor Pattern )

Java访问者模式 摘要实现范例 访问者模式&#xff08;Visitor Pattern&#xff09;使用了一个访问者类&#xff0c;它改变了元素类的执行算法&#xff0c;通过这种方式&#xff0c;元素的执行算法可以随着访问者改变而改变访问者模式中&#xff0c;元素对象已接受访问者对象&a…

Unity2019.2.x 导出apk 安装到安卓Android12+及以上的系统版本 安装出现-108 安装包似乎无效的解决办法

Unity2019.2.x 导出apk 安装到安卓Android12及以上的系统版本 安装出现-108 安装包似乎无效的解决办法 导出AndroidStudio工程后 需要设置 build.gradle文件 // GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAINbuildscript {repositor…

python-0007-django模版

介绍 模版是对js&#xff0c;html等资源的封装 新建 在项目路径下新建模版文件夹templates&#xff08;可以为其他名称&#xff09;&#xff0c;要是想细分业务的话&#xff0c;还可以在templates路径下继续建文件夹。如下图&#xff1a; 注册模版 在项目的settings找到T…

超越营销:交易性邮件如何塑造现代沟通

在我们的电子邮件自动化系列文章中&#xff0c;我们继续探讨交易性邮件的重要性。这些邮件对于向收件人传递实时更新和可操作信息至关重要&#xff0c;是企业运营不可或缺的一部分。 运营触点 在现代沟通中&#xff0c;交易性邮件扮演着不可或缺的角色&#xff0c;尤其是在企…

String类及其常用方法

文章目录 1.String类的特性与使用1.1 String类的特性1.2 String对象的创建方式1.3 String 的使用&#xff08;不同的拼接操作&#xff09; 2.String常用方法2.1 String的常用方法一2.2 String常用方法二2.3 String常用方法三 1.String类的特性与使用 1.1 String类的特性 Stri…

使用Barrier共享鼠标键盘,通过macos控制ubuntu系统

之前文章写过如何使用barrrier通过windows系统控制ubuntu系统&#xff0c;该文章将详细介绍如何使用barrier通过macos系统控制ubuntu系统 一、macOS安装barrier macOS版本barrier链接 1、双击点开安装包 2、将安装包里的barrier拷贝到macOS的达达->应用程序中 3、在达达…

Spring启动“--”设置参数没生效

现象 在idea中启动SpringBoot项目时&#xff0c;使用“--”设置的启动参数没有生效&#xff0c;如修改端口号“--server.port8082” 原因 排查发现是因为在使用SpringApplication.run启动项目时&#xff0c;没有将args参数传入run方法。 修复方案 SpringApplication.run参数中…

当matplotlib遇见“赛博朋克”

本次分享一个Python可视化工具cyberpunk,轻松让图表变得“赛博朋克”。 案例1 import matplotlib.pyplot as plt import mplcyberpunkplt.style.use("cyberpunk") #调用cyberpunk styleplt.plot([1, 3, 9, 5, 2, 1, 1], marker=o) plt.plot([4, 5, 5, 7, 9, 8, 6…

Linux系统——Nginx脚本拦截拓展

可能会有些无聊的人对服务器的Nginx服务进行恶意访问网站、API接口&#xff0c;会影响到用户的体验&#xff0c;我们可以做一个简单的脚本对恶意访问的IP做一个有效的拦截&#xff0c;揪出这些IP地址&#xff0c;然后将其进行禁用。 在Nginx的conf目录下新建一个blockip.conf文…

Redis第8讲——Cluster集群模式详解

前面两篇文章介绍了Redis主从和哨兵模式&#xff0c;不难发现&#xff0c;它们都有一些共同的缺点&#xff0c;首先在主从切换的过程中会丢失数据&#xff1b;另一个就是只有一个master&#xff0c;只能单点写&#xff0c;并没有水平扩容能力。而且每个节点都保存了所有的数据&…

sqlite3——数据库——day2

今天学习了sqlite3数据库 sqlite3_open sqlite3_openint sqlite3_open(const char *filename, /* Database filename (UTF-8) */sqlite3 **ppDb /* OUT: SQLite db handle */); 功能:打开数据库文件(创建一个数据库连接) 参数:filename:数据库文件路径 ppDb:操作数…
最新文章