缓存在开发中是一个必不可少的优化点,近期在项目重构中,有关缓存问题,花费大量的时间去做优化,比如在加载数据比较所的场景中,使用缓存机制来提高接口的响应速度,间接的提高用户体验。对于缓存,很多开发者对它都是既爱又恨,爱它的是:能够大幅度提升响应效率,恨的是:如果缓存处理不好、没有用好缓存策略,没有及时更新数据库的数据就会导致数据产生滞后,从而导致用户体验较差。这是一个很严重的老大难的问题,例如我在开发某项功能需要和其他项目进行对接的时候,线上总是出现我推送接口数据成功但是网站数据滞后的现象,询问对方的技术人员,得到的回复是缓存问题,只要删除缓存就没事了,我只能无奈了……所有说如何处理好缓存,对于我们开发人员来说,是一个极其棘手的问题。值得庆幸的是,SpringBoot已经提供给开发者很便捷的开发工作,废话不多了,接下来开始探索SpringBoot的缓存如何使用吧!
Spring 从3.1 版本开始就定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术,Cache 接口下 Spring 提供了各种的xxxCache的实现,例如RedisCache、EhCacheCache、ConcurrentMapCache等。每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否已经被调用过。如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户,下次调用直接从缓存中获取。
重要概念以及缓存注解
缓存注解
名称
解释
Cache |
缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等 |
CacheManager |
缓存管理器,管理各种缓存(cache)组件 |
@Cacheable |
主要针对方法配置,能够根据方法的请求参数对其进行缓存。主要实现的功能在进行一个读操作的时候,先从缓存中查询,如果查找不到,在读取数据库。这是缓存的注解最重要的一个方法,基本上我们的所有缓存实现都要依赖于它 |
@CacheEvict |
主要是配合@Cacheable一起使用的,它的主要作用就是清除缓存。当方法进行一些更新、删除操作的时候,就需要删除缓存 |
@CachePut |
这个注解它总是会把数据缓存,而不会去每次做检查它是否存在 。与@Cacheable区别在于是否每次都调用方法,常用于更新 |
@EnableCaching |
开启基于注解的缓存,主要作用就是全局配置缓存 |
keyGenerator |
缓存数据时key生成策略 |
serialize |
缓存数据时value序列化策略 |
@CacheConfig |
统一配置本类的缓存注解的属性 |
@Cacheable/@CachePut/@CacheEvict 主要的参数
名称
解释
value |
缓存的名称,在 spring 配置文件中定义,必须指定至少一个。例如: @Cacheable(value=”mycache”) 或者@Cacheable(value={”cache1”,”cache2”} |
key |
缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合。例如:@Cacheable(value=”testcache”,key=”#id”) |
condition |
缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存/清除缓存。@Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
unless |
否定缓存。当条件结果为TRUE时,就不会缓存。@Cacheable(value=”testcache”,unless=”#userName.length()>2”) |
allEntries(@CacheEvict ) |
是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存。 @CachEvict(value=”testcache”,allEntries=true) |
beforeInvocation(@CacheEvict) |
是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存@CachEvict(value=”testcache”,beforeInvocation=true) |
springBoot开启注解
开始使用前需要导入依赖
<!-- Springboot devtools热部署配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- 引入lombok 依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<!-- 引入cache 缓存依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--MySQL依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 引入 MyBatis依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
在启动类注解@EnableCaching开启缓存
@SpringBootApplication
@EnableCaching //开启缓存
public class CacheApplication{
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class, args);
}
}
缓存@Cacheable
@Cacheable注解会先查询是否已经有缓存,有会使用缓存,没有则会执行方法并缓存
@Cacheable(key = "#id", unless = "#result.state==0")
public list<SysUser> getLists(Integer uid){
return cacheDao.getListsByUid(uid);
}
到这里,可以运行程序检验缓存功能是否实现了。如有兴趣的话,也可以深入源码,查看其他的属性,这里简单的说下。
String[] cacheNames() default {}; //和value注解差不多,二选一
String keyGenerator() default ""; //key的生成器。key/keyGenerator二选一使用
String cacheManager() default ""; //指定缓存管理器
String cacheResolver() default ""; //或者指定获取解析器
String condition() default ""; //条件符合则缓存
String unless() default ""; //条件符合则不缓存
boolean sync() default false; //是否使用异步模式
配置@CacheConfig
当我们需要缓存的地方越来越多,你可以使用@CacheConfig(cacheNames = {"myCache"})注解来统一指定value的值,这时可省略value,如果你在你的方法依旧写上了value,那么依然以方法的value值为准。
@Service
@CacheConfig(cacheNames = "articleCache")
public class ArticleService {
……
}
CacheConfig 的属性
String keyGenerator() default ""; //key的生成器。key/keyGenerator二选一使用
String cacheManager() default ""; //指定缓存管理器
String cacheResolver() default ""; //或者指定获取解析器
更新@CachePut
@CachePut注解的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用 。简单来说就是用户更新缓存数据。但需要注意的是该注解的value 和 key 必须与要更新的缓存相同,也就是与@Cacheable 相同。示例:
@CachePut(value = "cacheTemp", key = "targetClass + #p0")
public SysUser updata(SysUser sysUser) {
SysUser sysUser = sysUserDao.findAllById(sysUser.getId());
sysUserDao.updata(sysUser);
return sysUser;
}
@Cacheable(value = "cacheTemp", key = "targetClass +#p0")//清空缓存
public SysUser save(SysUser sysUser) {
sysUserDao.save(sysUser);
return sysUser;
}
CachePut 其他的属性
String[] cacheNames() default {}; //与value二选一
String keyGenerator() default ""; //key的生成器。key/keyGenerator二选一使用
String cacheManager() default ""; //指定缓存管理器
String cacheResolver() default ""; //或者指定获取解析器
String condition() default ""; //条件符合则缓存
String unless() default ""; //条件符合则不缓存
清除@CacheEvict
@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空 。
@Cacheable(value = "cacheTemp",key = "#id")
public SysUser save(SysUser job) {
……
}
//清除一条缓存,key为要清空的数据
@CacheEvict(value="cacheTemp",key="#id")
public void delect(int id) {
……
}
//方法调用后清空所有缓存
@CacheEvict(value="accountCache",allEntries=true)
public void delectAll() {
……
}
//方法调用前清空所有缓存
@CacheEvict(value="accountCache",beforeInvocation=true)
public void delectAll() {
……
}
其他属性
String[] cacheNames() default {}; //与value二选一
String keyGenerator() default ""; //key的生成器。key/keyGenerator二选一使用
String cacheManager() default ""; //指定缓存管理器
String cacheResolver() default ""; //或者指定获取解析器
String condition() default ""; //条件符合则清空
测试
这里使用postman模拟接口请求
执行插入操作
首先我们来增加一篇文章:请求add接口
后台返回表示成功:
从后台数据库看到已经插入数据,它的id是1
执行查询操作
在查询操作中,getArticle,我使用线程睡眠的方式,模拟了5秒的时间来处理耗时性业务,第一次请求肯定会查询数据库,理论上第二次请求,将会走缓存,我们来测试一下:首先执行查询操作
接口响应成功,再看一下后台打印:表示执行了一次查询操作,耗时5212秒
好,重点来了,我们再次请求接口看看会返回什么?
与上面的比对,这次没有打印执行数据库查询操作,证明没有走数据库,并且耗时只有3ms,成功了!缓存发挥作用,从5212秒减小到3秒!大大提升了响应速度,
执行更新操作
当我们进行修改操作的时候,我们希望缓存的数据被清空:
后台控制台打印:
接下来,连续请求三次请求查询接口,看看会返回什么?
第一次请求以及结果
连续三次调用查询接口,虽然每次返回的都是相同的结果,看上去没有什么不同,但是我却有很明显的感受,就是第一次查询最慢,第二次、第三次查询特别快。第一次查询耗时是5063毫秒,第二次、第三次耗时确实0,这是因为当我们第一次执行id=2的数据库查询操作,那个时候缓存已被清空,是从数据库中获取的最新数据并放进缓存,然后后面的几次查询都是直接从缓存中获取数据,所以查询速度很快。
执行删除操作
在删除操作中,执行了一次删除,那么缓存也会被清空,查询的时候会再次走数据库,这里就不在具体展示了。
总结
如何在开发中使用缓存?怎样合理的使用都是值得我们学习的地方,缓存能大大提升程序的响应速度,提升用户体验,不过它适用的场景也是读多写少的业务场景,如果数据频繁修改,缓存将会失去意义,每次还是执行的数据库操作!这里只是探讨了Spring的注解缓存,相对来说还是比较简单的,希望起到抛砖引玉的作用.
相关推荐
总的来说,"springboot-redis缓存+分布锁"项目是学习如何在SpringBoot应用中使用Redis进行缓存管理和实现分布式锁的绝佳实践。通过这个项目,你可以深入了解SpringBoot的集成特性,以及Redis在高并发场景下的重要...
本资源提供了一个系统的SpringBoot学习课程大纲,旨在帮助学习者快速掌握SpringBoot技术,提高学习者的开发能力和解决问题的能力。 Spring Boot基础篇学习目标: * 能够创建SpringBoot工程 * 基于SpringBoot实现...
在本案例实战中,我们将...在这个案例实战中,我们学习了如何配置Redis连接,如何使用`@Cacheable`注解实现缓存,以及如何处理分页查询。这个源码包`spring-redis-demo`提供了完整的示例代码,可供进一步研究和实践。
SpringBoot新手学习手册是针对Java开发者的指南,旨在帮助初学者快速掌握SpringBoot框架的使用。SpringBoot简化了Spring应用程序的构建过程,减少了XML配置,提供了开箱即用的功能,并内置了Tomcat等Web服务器。 1....
《SpringBoot学习PDF》这份资料全面且深入地探讨了Spring Boot这一流行的Java开发框架。Spring Boot简化了Spring应用的初始搭建以及开发过程,它通过提供预配置的starter、自动配置和命令行接口(CLI)等功能,让...
SpringBoot因其简化开发流程、内置Tomcat服务器和自动配置特性,已经成为现代Java Web应用的首选框架之一。而Redis作为一款内存数据结构存储系统,常用于实现高性能的缓存服务,能够显著提高系统的响应速度。 首先...
**SpringBoot 快速学习项目概述** SpringBoot 是由 Pivotal 团队提供的全新框架,旨在简化 Spring 应用程序的初始搭建以及开发过程。它集成了大量常用的第三方库配置,如 JDBC、MongoDB、JPA、RabbitMQ、Quartz ...
Spring Boot是Java开发者的首选框架,因为它简化了设置和配置,使得快速开发变得可能。声明式缓存允许我们在不修改业务代码的情况下添加缓存功能,而JDBC(Java Database Connectivity)是Java与数据库交互的标准API...
SpringBoot是企业级开发的整体整合解决方案,特别用于快速构建微服务应用,旨在用最简单的方式让开发人员适应各种开发场景。 SpringBoot全套视频分为上下两部;本视频《SpringBoot高级》属于下部,着重介绍...
这个"Springboot学习教程,Springboot精讲42课"涵盖了从基础到进阶的全面内容,非常适合想要深入理解和掌握SpringBoot技术的开发者。 在SpringBoot中,核心特性包括自动配置、起步依赖和命令行界面。自动配置是...
它提供了丰富的功能,包括但不限于IoC容器、数据访问/集成、Web框架、缓存、任务调度等。Spring Boot则是基于Spring框架构建的,旨在简化Spring应用的初始搭建和运行过程,通过默认配置减少开发者的工作量。 2. **...
这门课程覆盖了Spring Boot的基础知识,集成第三方技术,以及在实际开发中的各种应用场景,如Web开发、数据访问、缓存管理、安全管理和任务管理等。 在第一章节"Spring Boot开发入门"中,学习者将了解到Spring Boot...
【标题】:“SpringBoot与JPA整合开发” 在现代Java应用程序开发中,Spring Boot和Java Persistence API(JPA)的组合被广泛使用,为开发者提供了高效、便捷的框架支持。Spring Boot简化了Spring应用程序的初始设置...
在“基于mongodb数据库的集成redis缓存springboot实战”项目中,我们将学习如何将这两个技术结合在一起,以实现高效的数据存储和检索。首先,我们需要在SpringBoot项目中添加MongoDB和Redis的相关依赖。这通常通过在...
本文旨在深入探讨SpringBoot框架的特性及其在Web快速开发中的应用,为读者提供一个全面的学习资源。 SpringBoot是Pivotal团队开发的一款轻量级Java框架,其目的是简化基于Spring的应用程序的创建和开发过程。...
这是一个基于SpringBoot和Vue3开发的博客系统的源码包,非常适合初学者进行学习、二次开发,以及用作毕业设计或课程设计的项目实践。在这个项目中,你可以深入了解和掌握两个核心技术栈:Java后端的SpringBoot框架和...
在软件开发中,缓存机制是提高系统性能和增加系统吞吐量的重要手段之一。缓存可以将不经常改变得数据存放在访问速度更快的内存里或者是低延迟存储器,服务器上,从而避免直接访问数据库等低速存储系统。然而,在...
springboot学习资料 一、 Spring介绍 1 1.1、SpringBoot简介 1 1.2、系统要求: 1 二、快速入门 1 2.1、创建一个Maven工程 1 2.2、pom文件引入依赖 2 2.3、编写HelloWorld服务 2 2.4、@RestController 3 ...
SpringBoot学习总结 在深入探讨SpringBoot之前,我们先来了解一下Spring框架的发展历程。Spring作为Java企业级应用的基石,自2003年诞生以来,经历了从IoC容器、AOP面向切面编程到SpringMVC的演进,极大地简化了...