前言

Spring框架支持透明地向应用程序添加缓存对缓存进行管理,其管理缓存的核心是将缓存应用于操作数据的方法(包括增删查改等),从而减少操作数据的执行次数(主要是查询,直接从缓存中读取数据),同时不会对程序本身造成任何干扰

SpringBoot继承了Spring框架的缓存管理功能,通过使用@EnableCaching注解开启基于注解的缓存支持,SpringBoot就可以启动缓存管理的自动化配置

接下来针对SpringBoot支持的默认缓存管理进行讲解。

SpringBoot默认缓存管理

1、基础环境搭建

(1)准备数据

使用前面 SpringBoot数据访问(一) SpringBoot整合Mybatis 一文中创建的数据库springbootdata,该数据库中包含两张数据表:t_article和t_comment。

(2)创建项目,代码编写

1、在项目依赖中添加SQL模块的JPA依赖、MySql依赖以及Web模块中的Web依赖,如下图所示:

引入这三个依赖器创建项目,在项目pom.xml文件会出现以下依赖:

2、编写数据库表对应的实体类,并使用JPA相关注解配置映射关系

package com.hardy.springbootdatacache.entity;

import org.springframework.data.annotation.Id;

import javax.persistence.*;

/**
* @Author: HardyYao
* @Date: 2021/6/19
*/
@Entity(name = "t_comment") // 设置ORM实体类,并指定映射的表名
public class Comment { @Id // 映射对应的主键id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 设置主键自增策略
private Integer id; private String content; private String author; @Column(name = "a_id") // 指定映射的表字段名
private Integer aId; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getContent() {
return content;
} public void setContent(String content) {
this.content = content;
} public String getAuthor() {
return author;
} public void setAuthor(String author) {
this.author = author;
} public Integer getaId() {
return aId;
} public void setaId(Integer aId) {
this.aId = aId;
} @Override
public String toString() {
return "Comment{" +
"id=" + id +
", content='" + content + '\'' +
", author='" + author + '\'' +
", aId=" + aId +
'}';
}
}

3、编写数据库操作的Repository接口文件

package com.hardy.springbootdatacache.repository;

import com.hardy.springbootdatacache.entity.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional; /**
* @Author: HardyYao
* @Date: 2021/6/19
*/
public interface CommentRepository extends JpaRepository<Comment, Integer> { /**
* 根据评论id修改评论作者author
* @param author
* @param id
* @return
*/
@Transactional
@Modifying
@Query("update t_comment c set c.author = ?1 where c.id=?2")
int updateComment(String author,Integer id); }

4、编写service层

package com.hardy.springbootdatacache.service;

import com.hardy.springbootdatacache.entity.Comment;
import com.hardy.springbootdatacache.repository.CommentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import java.util.Optional; /**
* @Author: HardyYao
* @Date: 2021/6/19
*/
@Service
public class CommentService { @Autowired
private CommentRepository commentRepository; /**
* 根据评论id查询评论
* @Cacheable:将该方法的查询结果comment存放在SpringBoot默认缓存中
* cacheNames:起一个缓存命名空间,对应缓存唯一标识
* @param id
* @return
*/
@Cacheable(cacheNames = "comment")
public Comment findCommentById(Integer id){
Optional<Comment> comment = commentRepository.findById(id);
if(comment.isPresent()){
Comment comment1 = comment.get();
return comment1;
}
return null;
} }

5、编写controller层

package com.hardy.springbootdatacache.controller;

import com.hardy.springbootdatacache.entity.Comment;
import com.hardy.springbootdatacache.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; /**
* @Author: HardyYao
* @Date: 2021/6/19
*/
@RestController
public class CommentController { @Autowired
private CommentService commentService; @RequestMapping(value = "/findCommentById")
public Comment findCommentById(Integer id){
Comment comment = commentService.findCommentById(id);
return comment;
} }

6、编写配置文件

在全局配置文件application.properties中编写对应的数据库连接配置

# MySQL数据库连接配置
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
# 显示使用JPA进行数据库查询的SQL语句
spring.jpa.show-sql=true # 开启驼峰命名匹配映射
mybatis.configuration.map-underscore-to-camel-case=true
# 解决中文乱码问题
spring.http.encoding.force-response=true

7、测试

在浏览器中输入:http://localhost:8080/findCommentById?id=1 进行访问(连续访问三次):

在上图中,因为没有在SpringBoot项目中开启缓存管理,故虽然数据表中的数据没有任何变化,但是每执行一次查询操作,即便执行的是相同的SQL语句,都还是会访问一次数据库。

2、默认缓存使用

在前面搭建的Web应用的基础上,开启SpringBoot默认支持的缓存,以使用SpringBoot默认缓存。

1、在项目启动类的类名上方使用@EnableCaching注解开启基于注解的缓存支持

package com.hardy.springbootdatacache;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching; @EnableCaching // 开启SpringBoot基于注解的缓存管理支持
@SpringBootApplication
public class SpringbootdataCacheApplication { public static void main(String[] args) {
SpringApplication.run(SpringbootdataCacheApplication.class, args);
} }

2、使用@Cacheable注解对数据操作方法进行缓存管理

将@Cacheable注解标注在Service类的查询方法上,对查询结果进行缓存:

package com.hardy.springbootdatacache.service;

import com.hardy.springbootdatacache.entity.Comment;
import com.hardy.springbootdatacache.repository.CommentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import java.util.Optional; /**
* @Author: HardyYao
* @Date: 2021/6/19
*/
@Service
public class CommentService { @Autowired
private CommentRepository commentRepository; /**
* 根据评论id查询评论
* @param id
* @return
*/
@Cacheable(cacheNames = "comment")
public Comment findCommentById(Integer id){
Optional<Comment> comment = commentRepository.findById(id);
if(comment.isPresent()){
Comment comment1 = comment.get();
return comment1;
}
return null;
} }

3、测试访问

在浏览器中输入:http://localhost:8080/findCommentById?id=1 进行访问(连续访问三次):

可以看到,在使用SpringBoot默认缓存注解后,重复进行同样的查询操作,数据库只执行了一次SQL查询语句,说明项目开启的默认缓存支持已生效。

SpringBoot默认缓存底层结构:在诸多的缓存自动配置类中,SpringBoot默认装配的是SimpleCacheConfiguration,它使用的CacheManager是ConcurrentMapCacheManager,使用ConcurrentMap作为底层的数据结构,根据Cache的名字查询出Cache,每一个Cache中存在多个key-value键值对、缓存值。

4、缓存注解介绍

前面我们通过使用@EnableCaching、@Cacheable注解实现了SpringBoot默认的基于注解的缓存管理,除此之外,还有其它注解及注解属性也可用于配置优化缓存管理。下面,我们对@EnableCaching、@Cacheable及其他与缓存管理相关的注解进行介绍。

4.1、@EnableCaching注解

@EnableCaching注解是由Spring框架提供的,SpringBoot框架对该注解进行了继承,该注解需要配置在类的上方(一般配置在项目启动类上),用于开启基于注解的缓存支持。

4.2、@Cacheable注解

@Cacheable注解也是由Spring框架提供的,可以作用于类或方法上(通常作用于数据查询方法上),用于对方法的执行结果进行数据缓存存储。注解的执行顺序是:先进行缓存查询,如果为空则进行方法查询(查数据库),并将结果进行缓存;如果缓存中有数据,则不进行方法查询,而是直接使用缓存数据。

@Cacheable注解提供了多个属性,用于对缓存存储进行相关设置,如下所示:

执行流程&时机

方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取,(CacheManager先获取相应的缓存),第一次获取缓存如果获取不到,Cache组件会自动创建。

去Cache中查找缓存的内容,使用一个key进行查找,默认在只有一个参数的情况下,key值默认就是方法的参数;如果有多个参数或者没有参数,则SpringBoot会按照某种策略生成key,默认是使用KeyGenerator生成的,其实现类为SimpleKeyGenerator。

SimpleKeyGenerator生成key的默认策略:

常用的SPEL表达式:

4.3、@CachePut注解

目标方法执行完之后生效。@CachePut被使用于修改操作较多,若缓存中已经存在目标值了,该注解作用的方法依然会执行,执行后将结果保存在缓存中(覆盖掉原来的目标值)。

@CachePut注解也提供了多个属性,这些属性与@Cacheable注解的属性完全相同。

4.4、@CacheEvict注解

@CacheEvict注解也是由Spring框架提供的,可以作用于类或方法上(通常作用于数据删除方法上),该注解的作用是删除缓存数据。

@CacheEvict注解的默认执行顺序是:先进行方法调用,然后将缓存进行清除。

最新文章

  1. 【001:转载 ubuntu下: 建立本地SVN服务器】
  2. Python: Catch multiple exceptions in one line (except block)
  3. BZOJ 1455
  4. Windows Phone 8初学者开发—第17部分:Coding4Fun工具包简介
  5. java封装的方法
  6. 在VB6/VBA中使用正则表达式
  7. .NET垃圾回收机制 GC
  8. sql注入中关于--+的一点探索
  9. Chapter 5 Blood Type——10
  10. tensorflow中batch normalization的用法
  11. 自动化测试 | UI Automator 入门指南
  12. HDU 6315 Naive Operations(线段树区间整除区间)
  13. [leetcode]210. Course Schedule II课程表II
  14. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #21FUSE
  15. Windows注意目录
  16. SOAP与REST比较(转)
  17. mongoDB操作2
  18. [转]关于sdk更新Android SDK Tools 25.3.1版本后使用sdk manager闪退
  19. c++ 反射类型
  20. [洛谷P4168][Violet]蒲公英

热门文章

  1. Spring Cloud Alibaba Nacos Discovery 实战
  2. linux系统瓶颈分析(精) CPU Memory IO Network
  3. Keil编译后的Code,RO,RW,ZI分别表示什么以及和芯片Flash、SRAM的对应关系
  4. 删除win10系统下文件默认打开方式的关联-win10配置
  5. 大数据学习之路—环境配置——IP设置(虚拟机修改Ip的内在原因及实现)
  6. MongoDB学习笔记:文档Crud Shell
  7. Manjaro Linux安装singularity-container
  8. 五、SVM推导过程
  9. Asp.Net Core Api 使用Swagger管理文档教程的安装与使用
  10. 关于MongoDB ObjectId的那些事儿