点击上方蓝色“程序猿DD”,选择“设为星标”

回复“资源”获取独家整理的学习资料!

随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一。Spring 3开始提供了强大的基于注解的缓存支持,可以通过注解配置方式低侵入的给原有Spring应用增加缓存功能,提高数据访问性能。

在Spring Boot中对于缓存的支持,提供了一系列的自动化配置,使我们可以非常方便的使用缓存。下面我们通过一个简单的例子来展示,我们是如何给一个既有应用增加缓存功能的。

快速入门

下面我们将使用使用Spring Data JPA访问MySQL一文的案例为基础。这个案例中包含了使用Spring Data JPA访问User数据的操作,利用这个基础,我们为其添加缓存,来减少对数据库的IO,以达到访问加速的作用。如果您还不熟悉如何实现对MySQL的读写操作,那么建议先阅读前文,完成这个基础案例的编写。

先简单回顾下这个案例的基础内容:

User实体的定义

@Entity
@Data
@NoArgsConstructor
public class User {@Id@GeneratedValueprivate Long id;private String name;private Integer age;public User(String name, Integer age) {this.name = name;this.age = age;}
}

User实体的数据访问实现

public interface UserRepository extends JpaRepository<User, Long> {User findByName(String name);User findByNameAndAge(String name, Integer age);@Query("from User u where u.name=:name")User findUser(@Param("name") String name);}

为了更好的理解缓存,我们先对该工程做一些简单的改造。

  • application.properties文件中新增spring.jpa.show-sql=true,开启hibernate对sql语句的打印。如果是1.x版本,使用spring.jpa.properties.hibernate.show_sql=true参数。

  • 修改单元测试类,插入User表一条用户名为AAA,年龄为10的数据。并通过findByName函数完成两次查询,具体代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter51ApplicationTests {@Autowiredprivate UserRepository userRepository;@Testpublic void test() throws Exception {// 创建1条记录userRepository.save(new User("AAA", 10));User u1 = userRepository.findByName("AAA");System.out.println("第一次查询:" + u1.getAge());User u2 = userRepository.findByName("AAA");System.out.println("第二次查询:" + u2.getAge());}}

在没有加入缓存之前,我们可以先执行一下这个案例,可以看到如下的日志:

Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where user0_.name=?
第一次查询:10
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where user0_.name=?
第二次查询:10

两次findByName查询都执行了两次SQL,都是对MySQL数据库的查询。

引入缓存

第一步:在pom.xml中引入cache依赖,添加如下内容:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>

第二步:在Spring Boot主类中增加@EnableCaching注解开启缓存功能,如下:

@EnableCaching
@SpringBootApplication
public class Chapter51Application {public static void main(String[] args) {SpringApplication.run(Chapter51Application.class, args);}}

第三步:在数据访问接口中,增加缓存配置注解,如:

@CacheConfig(cacheNames = "users")
public interface UserRepository extends JpaRepository<User, Long> {@CacheableUser findByName(String name);}

第四步:再来执行以下单元测试,可以在控制台中输出了下面的内容

Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where user0_.name=?
第一次查询:10
第二次查询:10

到这里,我们可以看到,在调用第二次findByName函数时,没有再执行select语句,也就直接减少了一次数据库的读取操作。

为了可以更好的观察,缓存的存储,我们可以在单元测试中注入CacheManager

@Autowired
private CacheManager cacheManager;

使用debug模式运行单元测试,观察CacheManager中的缓存集users以及其中的User对象的缓存加深理解。

可以看到,在第一次调用findByName函数之后,CacheManager将这个查询结果保存了下来,所以在第二次访问的时候,就能匹配上而不需要再访问数据库了。

Cache配置注解详解

回过头来我们再来看这里使用到的两个注解分别作了什么事情:

  • @CacheConfig:主要用于配置该类中会用到的一些共用的缓存配置。在这里@CacheConfig(cacheNames = "users"):配置了该数据访问对象中返回的内容将存储于名为users的缓存对象中,我们也可以不使用该注解,直接通过@Cacheable自己配置缓存集的名字来定义。

  • @Cacheable:配置了findByName函数的返回值将被加入缓存。同时在查询时,会先从缓存中获取,若不存在才再发起对数据库的访问。该注解主要有下面几个参数:

    • valuecacheNames:两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了

    • key:缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:@Cacheable(key = "#p0"):使用函数第一个参数作为缓存的key值,更多关于SpEL表达式的详细内容可参考官方文档。

    • condition:缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表示只有当第一个参数的长度小于3的时候才会被缓存,若做此配置上面的AAA用户就不会被缓存,读者可自行实验尝试。

    • unless:另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。

    • keyGenerator:用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的

    • cacheManager:用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用

    • cacheResolver:用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。

除了这里用到的两个注解之外,还有下面几个核心注解:

  • @CachePut:配置于函数上,能够根据参数定义条件来进行缓存,它与@Cacheable不同的是,它每次都会真是调用函数,所以主要用于数据新增和修改操作上。它的参数与@Cacheable类似,具体功能可参考上面对@Cacheable参数的解析

  • @CacheEvict:配置于函数上,通常用在删除方法上,用来从缓存中移除相应数据。除了同@Cacheable一样的参数之外,它还有下面两个参数:

    • allEntries:非必需,默认为false。当为true时,会移除所有数据

    • beforeInvocation:非必需,默认为false,会在调用方法之后移除数据。当为true时,会在调用方法之前移除数据。

代码示例

本文的相关例子可以查看下面仓库中的chapter5-1目录:

  • Github:https://github.com/dyc87112/SpringBoot-Learning/

  • Gitee:https://gitee.com/didispace/SpringBoot-Learning/

如果您觉得本文不错,欢迎Star支持,您的关注是我坚持的动力!

往期推荐

Spring Boot 2.x基础教程:事务管理入门

Spring Boot 2.x基础教程:MyBatis的多数据源配置

Spring Boot 2.x基础教程:Spring Data JPA的多数据源配置

Spring Boot 2.x基础教程:JdbcTemplate的多数据源配置

Spring Boot 2.x基础教程:使用MyBatis的XML配置方式

Spring Boot 2.x基础教程:使用MyBatis访问MySQL

「程序猿 DD」星球活动第一期正式开启!点击了解!

立省 ¥100 ,到手仅 ¥99,即将 涨价至 ¥299

支持 3 天无理由退款,机不可失时不再来,赶紧加入吧 ~

Spring Boot 2.x基础教程:进程内缓存的使用与Cache注解详解相关推荐

  1. 开启注解缓存_Spring Boot 2.x基础教程:进程内缓存的使用与Cache注解详解

    随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一.Spring 3开始提供了强大的基于注解的缓 ...

  2. jeesite如何配置swagger_Spring Boot 2.x基础教程:Swagger接口分类与各元素排序问题详解...

    之前通过Spring Boot 2.x基础教程:使用Swagger2构建强大的API文档一文,我们学习了如何使用Swagger为Spring Boot项目自动生成API文档,有不少用户留言问了关于文档 ...

  3. Spring Boot 2.x基础教程:使用集中式缓存Redis

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 之前我们介绍了两种进程内缓存的用法,包括Spring B ...

  4. Spring Boot 2.x基础教程:使用JdbcTemplate访问MySQL数据库

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 翟永超 来源 | didispace.com/ ...

  5. Spring Boot 2.x基础教程:Swagger静态文档的生成

    前言 通过之前的两篇关于Swagger入门以及具体使用细节的介绍之后,我们已经能够轻松地为Spring MVC的Web项目自动构建出API文档了.如果您还不熟悉这块,可以先阅读: Spring Boo ...

  6. Spring Boot 2.x基础教程:使用EhCache缓存集群

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 上一篇我们介绍了在Spring Boot中整合EhCac ...

  7. Spring Boot 2.x基础教程:如何扩展XML格式的请求和响应

    在之前的所有Spring Boot教程中,我们都只提到和用到了针对HTML和JSON格式的请求与响应处理.那么对于XML格式的请求要如何快速的在Controller中包装成对象,以及如何以XML的格式 ...

  8. Spring Boot 2.x基础教程:多文件的上传

    昨天,我们介绍了如何在Spring Boot中实现文件的上传(博客地址:https://blog.didispace.com/spring-boot-learning-21-4-3/).有读者问:那么 ...

  9. Spring Boot 2.x基础教程:JSR-303实现请求参数校验

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 作者 | 翟永超 来源 | didispace.com/spring-boot-learni ...

  10. Spring Boot 2.x基础教程:使用LDAP来管理用户与组织数据

    很多时候,我们在做公司系统或产品时,都需要自己创建用户管理体系,这对于开发人员来说并不是什么难事,但是当我们需要维护多个不同系统并且相同用户跨系统使用的情况下,如果每个系统维护自己的用户信息,那么此时 ...

最新文章

  1. 两个关于水花的测试。
  2. 【 FPGA 】状态机,FPGA的灵魂
  3. 如何使CPU占用率为50%
  4. 性能测试服务器数量与线上数量不同,性能需求分析
  5. 在运行期通过反射了解JVM内部机制
  6. 乐易家智能机器人价格_安川焊接机器人价格多少钱?核心是质量好
  7. “雏鹰”的最近感想……
  8. 解决This picacion faied to trt becuse t could, not find or load the Qt platform plugin “windows““问题
  9. 你知道C#中的Lambda表达式的演化过程吗
  10. kalman滤波在雷达目标跟踪中的应用_简述Automotive radar中的多目标跟踪处理
  11. mysql 创建函数_MySQL文件及目录权限设置分析-爱可生
  12. 集合的创建、集合的特性(成员操作符、for循环)
  13. SOEM代码Slaveinfo Demo分析
  14. Html5用户注册页面
  15. UE4--地形篇——风吹草动的草
  16. 基于Arduino的智能环境监测与反馈系统
  17. 修改(移交)微信支付商户平台超级管理员账号流程
  18. vLive带你走进虚拟直播世界
  19. 轻松快速安装Kubernetes dashboard
  20. Android系统判断CPU是32位还是64位

热门文章

  1. ElasticSearch入门手册
  2. windows xp下无线网卡断线的问题。
  3. HealthKit框架指南
  4. 镜像翻转_《蒙娜丽莎》镜像翻转后,暗藏神秘的第二张脸?网友:笑容消失了...
  5. likeshop搭建商城系统,一步到位
  6. 华为s2600t java_华为S2600T------v1版本
  7. 您尝试安装的Adobe Flash Player版本不是最新版本解决办法
  8. 判断文件是否为图片格式
  9. PHP从入门到精通(数组运算符篇)
  10. 三相并网逆变器系统(光伏发电系统)simulink仿真