Spring Boot 2.X(七):Spring Cache 使用

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: Spring Cache 简介 在 Spring 3.1 中引入了多 Cache 的支持,在 spring-context 包中定义了org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 两个接口来统一不同的缓存技术。

Spring Cache 简介

在 Spring 3.1 中引入了多 Cache 的支持,在 spring-context 包中定义了org.springframework.cache.Cacheorg.springframework.cache.CacheManager 两个接口来统一不同的缓存技术。Cache 接口包含缓存的常用操作:增加、删除、读取等。CacheManager 是 Spring 各种缓存的抽象接口。
Spring 支持的常用 CacheManager 如下:

CacheManager 描述
SimpleCacheManager 使用简单的 Collection 来存储缓存
ConcurrentMapCacheManager 使用 java.util.ConcurrentHashMap 来实现缓存
NoOpCacheManager 仅测试用,不会实际存储缓存
EhCacheCacheManger 使用EhCache作为缓存技术。EhCache 是一个纯 Java 的进程内缓存框架,特点快速、精干,是 Hibernate 中默认的 CacheProvider,也是 Java 领域应用最为广泛的缓存
JCacheCacheManager 支持JCache(JSR-107)标准的实现作为缓存技术
CaffeineCacheManager 使用 Caffeine 作为缓存技术。用于取代 Guava 缓存技术。
RedisCacheManager 使用Redis作为缓存技术
HazelcastCacheManager 使用Hazelcast作为缓存技术
CompositeCacheManager 用于组合 CacheManager,可以从多个 CacheManager 中轮询得到相应的缓存

Spring Cache 提供了 @Cacheable 、@CachePut 、@CacheEvict 、@Caching 等注解,在方法上使用。通过注解 Cache 可以实现类似事务一样、缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码。
核心思想:当我们调用一个方法时会把该方法的参数和返回结果最为一个键值对存放在缓存中,等下次利用同样的参数来调用该方法时将不会再执行,而是直接从缓存中获取结果进行返回。

Cache注解

1.@EnableCaching

开启缓存功能,一般放在启动类上。

2.@CacheConfig

当我们需要缓存的地方越来越多,你可以使用@CacheConfig(cacheNames = {"cacheName"})注解在 class 之上来统一指定value的值,这时可省略value,如果你在你的方法依旧写上了value,那么依然以方法的value值为准。

3.@Cacheable

根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上
查看源码,属性值如下:

属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key
keyGenerator key的生成器。key/keyGenerator二选一使用
cacheManager 指定缓存管理器
cacheResolver 指定获取解析器
condition 条件符合则缓存
unless 条件符合则不缓存
sync 是否使用异步模式,默认为false

4.@CachePut

使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上
查看源码,属性值如下:

属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key
keyGenerator key的生成器。key/keyGenerator二选一使用
cacheManager 指定缓存管理器
cacheResolver 指定获取解析器
condition 条件符合则缓存
unless 条件符合则不缓存

5.@CacheEvict

使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上
查看源码,属性值如下:

属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key
keyGenerator key的生成器。key/keyGenerator二选一使用
cacheManager 指定缓存管理器
cacheResolver 指定获取解析器
condition 条件符合则缓存
allEntries 是否清空所有缓存,默认为 false。如果指定为 true,则方法调用后将立即清空所有的缓存
beforeInvocation 是否在方法执行前就清空,默认为 false。如果指定为 true,则在方法执行前就会清空缓存

6.@Caching

该注解可以实现同一个方法上同时使用多种注解。可从其源码看出:

public @interface Caching {

    Cacheable[] cacheable() default {};

    CachePut[] put() default {};

    CacheEvict[] evict() default {};

}

Spring Cache 使用

1.构建项目,添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.zwqh</groupId>
    <artifactId>spring-boot-cache</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-boot-cache</name>
    <description>spring-boot-cache</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Cache -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <!-- jdbc -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- 热部署模块 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional> <!-- 这个需要为 true 热部署才有效 -->
        </dependency>


        <!-- mysql 数据库驱动. -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- mybaits -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.application.properties 配置文件

#datasource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/db_test?useUnicode=true&characterEncoding=UTF-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=123456
#mybatis
mybatis.mapper-locations=classpath:/mapper/*Mapper.xml

3.实体类

public class UserEntity implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 5237730257103305078L;
    private Long id;
    private String userName;
    private String userSex;
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getUserSex() {
        return userSex;
    }
    public void setUserSex(String userSex) {
        this.userSex = userSex;
    }
    
}

4.数据层 dao 和 mapper.xml

public interface UserDao {
    //mapper.xml方式 
    /**
     * 获取所有用户
     * @return
     */
    List<UserEntity> getAll();
    /**
     * 根据id获取用户
     * @return
     */
    UserEntity getOne(Long id);
    /**
     * 新增用户
     * @param user
     */
    void insertUser(UserEntity user);
    /**
     * 修改用户
     * @param user
     */
    void updateUser(UserEntity user);
    /**
     * 删除用户
     * @param id
     */
    void deleteUser(Long id);
        

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.4//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.zwqh.springboot.dao.UserDao">
    <resultMap type="cn.zwqh.springboot.model.UserEntity" id="user">
        <id property="id" column="id"/>
        <result property="userName" column="user_name"/>
        <result property="userSex" column="user_sex"/>
    </resultMap>
    <!-- 获取所有用户 -->
    <select id="getAll" resultMap="user">
        select * from t_user
    </select>
    <!-- 根据用户ID获取用户 -->
    <select id="getOne" resultMap="user">
        select * from t_user where id=#{id}
    </select>
    <!-- 新增用户 -->
    <insert id="insertUser" parameterType="cn.zwqh.springboot.model.UserEntity">
        insert into t_user (user_name,user_sex) values(#{userName},#{userSex})
    </insert>
    <!-- 修改用户 -->
    <update id="updateUser" parameterType="cn.zwqh.springboot.model.UserEntity">
        update t_user set user_name=#{userName},user_sex=#{userSex} where id=#{id}
    </update>
    <!-- 删除用户 -->
    <delete id="deleteUser" parameterType="Long">
        delete from t_user where id=#{id}
    </delete>
</mapper>

5.业务代码层接口 Service 和实现类 ServiceImpl

public interface UserService {

    /**
     * 查找所有
     * @return
     */
    List<UserEntity> getAll();
    /**
     * 根据id获取用户
     * @param id
     * @return
     */
    UserEntity getOne(Long id);
    /**
     * 新增用户
     * @param user
     */
    void insertUser(UserEntity user);
    /**
     * 修改用户
     * @param user
     */
    void updateUser(UserEntity user);
    
    void deleteAll1();
    
    void deleteAll12();
}
@Service
@CacheConfig(cacheNames = {"userCache"})
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    @Cacheable("userList") // 标志读取缓存操作,如果缓存不存在,则调用目标方法,并将结果放入缓存
    public List<UserEntity> getAll() {
        System.out.println("缓存不存在,执行方法");
        return userDao.getAll();
    }

    @Override
    @Cacheable(cacheNames = { "user" }, key = "#id")//如果缓存存在,直接读取缓存值;如果缓存不存在,则调用目标方法,并将结果放入缓存
    public UserEntity getOne(Long id) {
        System.out.println("缓存不存在,执行方法");
        return userDao.getOne(id);
    }

    @Override
    @CachePut(cacheNames = { "user" }, key = "#user.id")//写入缓存,key为user.id,一般该注解标注在新增方法上
    public void insertUser(UserEntity user) {
        System.out.println("写入缓存");
        userDao.insertUser(user);
    }

    @Override
    @CacheEvict(cacheNames = { "user" }, key = "#user.id")//根据key清除缓存,一般该注解标注在修改和删除方法上
    public void updateUser(UserEntity user) {
        System.out.println("清除缓存");
        userDao.updateUser(user);
    }
    
    @Override
    @CacheEvict(value="userCache",allEntries=true)//方法调用后清空所有缓存
    public void deleteAll1() {
    
    }
    
    @Override
    @CacheEvict(value="userCache",beforeInvocation=true)//方法调用前清空所有缓存
    public void deleteAll2() {

    }

}

6.测试 Controller

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     *  查找所有
     * @return
     */
    @RequestMapping("/getAll")
    public List<UserEntity> getAll(){
        return userService.getAll(); 
    }
    /**
     * 根据id获取用户
     * @return
     */
    @RequestMapping("/getOne")
    public UserEntity getOne(Long id){
        return userService.getOne(id); 
    }
    /**
     * 新增用户
     * @param user
     * @return
     */
    @RequestMapping("/insertUser")
    public String insertUser(UserEntity user) {
        userService.insertUser(user);
        return "insert success";
    }    
    /**
     * 修改用户
     * @param user
     * @return
     */
    @RequestMapping("/updateUser")
    public String updateUser(UserEntity user) {
        userService.updateUser(user);
        return "update success";
    }
}

7.启动 Cache 功能

@SpringBootApplication
@MapperScan("cn.zwqh.springboot.dao")
@EnableCaching //启动 Cache 功能
public class SpringBootCacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootCacheApplication.class, args);
    }

}

8.数据库及测试数据

数据库和测试数据仍旧用之前的。

9.测试

编写单元测试,或者通过访问 http://127.0.0.1:8080/user/ 加上对应路径和参数。

文档

org.springframework.cache

示例代码

github

码云

非特殊说明,本文版权归 朝雾轻寒 所有,转载请注明出处.

原文标题:Spring Boot 2.X(七):Spring Cache 使用

原文地址: https://www.zwqh.top/article/info/13

如果文章对您有帮助,请扫码关注下我的公众号,文章持续更新中...

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
7天前
|
前端开发 Java 应用服务中间件
《深入理解Spring》 Spring Boot——约定优于配置的革命者
Spring Boot基于“约定优于配置”理念,通过自动配置、起步依赖、嵌入式容器和Actuator四大特性,简化Spring应用的开发与部署,提升效率,降低门槛,成为现代Java开发的事实标准。
|
7天前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
15天前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
159 2
|
1月前
|
人工智能 Java 机器人
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
Spring AI Alibaba集成Ollama,基于Java构建本地大模型应用,支持流式对话、knife4j接口可视化,实现高隐私、免API密钥的离线AI服务。
850 1
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
存储 JSON Java
318 0
|
1月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
2月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
482 3
|
3月前
|
存储 缓存 NoSQL
Spring Cache缓存框架
Spring Cache是Spring体系下的标准化缓存框架,支持多种缓存(如Redis、EhCache、Caffeine),可独立或组合使用。其优势包括平滑迁移、注解与编程两种使用方式,以及高度解耦和灵活管理。通过动态代理实现缓存操作,适用于不同业务场景。
367 0