SpringBoot继承了Spring框架的缓存管理功能, 通过使用@EnableCaching注解开启基于注解的缓存支持,SpringBoot就可以启动缓存管理的自动化配置 。
接下来针对SpringBoot支持的默认缓存管理进行讲解。
使用该数据库中包含两张数据表:t_article和t_comment。
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{ /** * 根据评论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){ Optionalcomment = 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语句,都还是会访问一次数据库。
在前面搭建的Web应用的基础上,开启SpringBoot默认支持的缓存,以使用SpringBoot默认缓存。
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); } }
将@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){ Optionalcomment = commentRepository.findById(id); if(comment.isPresent()){ Comment comment1 = comment.get(); return comment1; } return null; } }
在浏览器中输入:http://localhost:8080/findCommentById?id=1 进行访问(连续访问三次):
可以看到,在使用SpringBoot默认缓存注解后,重复进行同样的查询操作,数据库只执行了一次SQL查询语句,说明项目开启的默认缓存支持已生效。
SpringBoot默认缓存底层结构:在诸多的缓存自动配置类中,SpringBoot默认装配的是SimpleCacheConfiguration,它使用的CacheManager是ConcurrentMapCacheManager,使用ConcurrentMap作为底层的数据结构,根据Cache的名字查询出Cache,每一个Cache中存在多个key-value键值对、缓存值。
前面我们通过使用@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注解的默认执行顺序是:先进行方法调用,然后将缓存进行清除。