SpringCache完整案例介绍

简介: Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager 接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们开发;Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache ,ConcurrentMapCache等;本文我们就来介绍下SpringCache的具体使用。

Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager 接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们开发;Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache ,ConcurrentMapCache等;本文我们就来介绍下SpringCache的具体使用。


一、缓存中的重要概念

截屏2021-12-03 上午10.44.21.png


@Cacheable/@CachePut/@CacheEvict 主要的参数

截屏2021-12-03 上午10.44.28.png


二、SpEL上下文数据


Spring Cache提供了一些供我们使用的SpEL上下文数据,下表直接摘自Spring官方文档

截屏2021-12-03 上午10.44.40.png


注意:


当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。 如

 @Cacheable(key = “targetClass + methodName +#p0”)


使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。 如:

 @Cacheable(value=“users”, key="#id")

 @Cacheable(value=“users”, key="#p0")


三、SpringCache的使用


1.导入依赖

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


2.然后在启动类注解@EnableCaching开启缓存


20191128124725183.png


3.创建业务类

package com.dpb.springboot.service;
import com.dpb.springboot.pojo.User;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
/**
 * @program: springboot-13-cache
 * @description:
 * @author: 波波烤鸭
 * @create: 2019-11-27 21:25
 */
@Service
public class UserService {
    /**
     * @Cacheable注解会先查询是否已经有缓存,有会使用缓存,没有则会执行方法并缓存
     * 此处的User实体类一定要实现序列化public class User implements Serializable,否则会报java.io.NotSerializableException异常。
     * @param userName
     * @return
     */
    @Cacheable(value = "userCache" , key = "#userName")
    public User getUserByName(String userName){
        System.out.println("数据库查询...." + userName);
        return getFromDB(userName);
    }
    /**
     * 清除一条记录
     * @param user
     */
    @CacheEvict(value = "userCache",key = "#user.name")
    public void updateUser(User user){
        System.out.println("数据更新了。。。。数据库");
        updateDB(user);
    }
    /**
     * allEntries:是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存
     * beforeInvocation:是否在方法执行前就清空,缺省为 false,如果指定为 true,
     *          则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存
     */
    @CacheEvict(value = "userCache",allEntries = true,beforeInvocation = true)
    public void reload(){
        //
    }
    private User getFromDB(String userName){
        System.out.println("查询数据库..." + userName);
        return new User(666,userName);
    }
    private void updateDB(User user){
        System.out.println("更新数据..." + user.getName());
    }
}


4.创建缓存实现类


 我们自定义一个基于内存的缓存实现 Cache接口,并实现相关的方法

package com.dpb.springboot.cache;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
/**
 * @program: springboot-13-cache
 * @description:
 * @author: 波波烤鸭
 * @create: 2019-11-27 21:32
 */
public class MyCache implements Cache {
    // 缓存的 key
    private String name;
    // 保存缓存数据的容器
    private Map<String,Object> store = new ConcurrentHashMap<>();
    public MyCache() {
    }
    public MyCache(String name) {
        this.name = name;
    }
    @Override
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 返回数据容器
     * @return
     */
    @Override
    public Object getNativeCache() {
        return store;
    }
    /**
     * 返回缓存数据
     * @param key
     * @return
     */
    @Override
    public ValueWrapper get(Object key) {
        ValueWrapper result = null;
        Object thevalue = store.get(key);
        if(thevalue != null){
            result = new SimpleValueWrapper(thevalue);
            System.out.println("执行了缓存查询...命中" + key);
        }else{
            System.out.println("执行了缓存查询...没有命中" + key);
        }
        return result;
    }
    /**
     * 返回缓存数据  基于泛型
     * @param key
     * @param aClass
     * @param <T>
     * @return
     */
    @Override
    public <T> T get(Object key, Class<T> aClass) {
        return aClass.cast(store.get(key));
    }
    @Override
    public <T> T get(Object o, Callable<T> callable) {
        return null;
    }
    /**
     * 保存缓存数据
     * @param o
     * @param o1
     */
    @Override
    public void put(Object o, Object o1) {
        //
        System.out.println("数据缓存了..." + o);
        store.put((String)o,o1);
    }
    /**
     * 清除一条缓存数据
     * @param key
     */
    @Override
    public void evict(Object key) {
        System.out.println("移走了元素:" + key);
        store.remove(key);
    }
    /**
     * 清空所有的数据
     */
    @Override
    public void clear() {
        store.clear();
    }
}


5.配置缓存管理器

20191128124912242.png


Spring的配置文件中如下配置


20191128124926482.png

6.测试代码

package com.dpb.springboot;
import com.dpb.springboot.pojo.User;
import com.dpb.springboot.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Springboot13CacheApplicationTests {
    @Autowired
    private UserService service ;
    @Test
    void contextLoads() {
        System.out.println("第一次查询...");
        service.getUserByName("hello");
        System.out.println("第二次查询...");
        service.getUserByName("hello");
        System.out.println("*************");
        // 更新记录
        User user1 = service.getUserByName("user1");
        // 开始更新其中一个
        user1.setId(1111);
        service.updateUser(user1);
        // 更新后再查询
        service.getUserByName("user1");
        // 再次查询
        service.getUserByName("user1");
        // 更新所有
        service.reload();
        System.out.println("清空了所有的缓存...");
        service.getUserByName("user1");
        service.getUserByName("user2");
        service.getUserByName("user1");
        service.getUserByName("user2");
    }
}


测试结果

第一次查询...
执行了缓存查询...没有命中hello
数据库查询....hello
查询数据库...hello
数据缓存了...hello
第二次查询...
执行了缓存查询...命中hello
*************
执行了缓存查询...没有命中user1
数据库查询....user1
查询数据库...user1
数据缓存了...user1
数据更新了。。。。数据库
更新数据...user1
移走了元素:user1
执行了缓存查询...没有命中user1
数据库查询....user1
查询数据库...user1
数据缓存了...user1
执行了缓存查询...命中user1
清空了所有的缓存...
执行了缓存查询...没有命中user1
数据库查询....user1
查询数据库...user1
数据缓存了...user1
执行了缓存查询...没有命中user2
数据库查询....user2
查询数据库...user2
数据缓存了...user2
执行了缓存查询...命中user1
执行了缓存查询...命中user2


搞定~


相关文章
|
6月前
|
存储 缓存 Java
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
|
6月前
|
缓存 NoSQL Java
Spring Cache 缓存原理与 Redis 实践
Spring Cache 缓存原理与 Redis 实践
350 0
|
存储 缓存 NoSQL
快速入门:Spring Cache
快速入门:Spring Cache
86 0
|
6月前
|
XML 存储 缓存
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache管理器的实战开发指南(修正篇)
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache管理器的实战开发指南(修正篇)
114 0
|
5月前
|
缓存 NoSQL Java
在 Spring Boot 应用中使用 Spring Cache 和 Redis 实现数据查询的缓存功能
在 Spring Boot 应用中使用 Spring Cache 和 Redis 实现数据查询的缓存功能
286 0
|
6月前
|
缓存 NoSQL Java
Spring Boot 3 整合 Spring Cache 与 Redis 缓存实战
Spring Boot 3 整合 Spring Cache 与 Redis 缓存实战
|
3月前
|
缓存 NoSQL Java
SpringBoot的三种缓存技术(Spring Cache、Layering Cache 框架、Alibaba JetCache 框架)
Spring Cache 是 Spring 提供的简易缓存方案,支持本地与 Redis 缓存。通过添加 `spring-boot-starter-data-redis` 和 `spring-boot-starter-cache` 依赖,并使用 `@EnableCaching` 开启缓存功能。JetCache 由阿里开源,功能更丰富,支持多级缓存和异步 API,通过引入 `jetcache-starter-redis` 依赖并配置 YAML 文件启用。Layering Cache 则提供分层缓存机制,需引入 `layering-cache-starter` 依赖并使用特定注解实现缓存逻辑。
1055 1
SpringBoot的三种缓存技术(Spring Cache、Layering Cache 框架、Alibaba JetCache 框架)
|
6月前
|
存储 XML 缓存
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南(一)
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南
460 0
|
6月前
|
缓存 NoSQL Java
Spring Cache之本地缓存注解@Cacheable,@CachePut,@CacheEvict使用
SpringCache不支持灵活的缓存时间和集群,适合数据量小的单机服务或对一致性要求不高的场景。`@EnableCaching`启用缓存。`@Cacheable`用于缓存方法返回值,`value`指定缓存名称,`key`定义缓存键,可按SpEL编写,`unless`决定是否不缓存空值。当在类上使用时,类内所有方法都支持缓存。`@CachePut`每次执行方法后都会更新缓存,而`@CacheEvict`用于清除缓存,支持按键清除或全部清除。Spring Cache结合Redis可支持集群环境。
401 6
|
5月前
|
缓存 网络协议 Java
Spring Cache
Spring Cache
31 0
下一篇
无影云桌面