前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCache完整案例介绍

SpringCache完整案例介绍

作者头像
用户4919348
发布2019-11-29 10:11:13
7710
发布2019-11-29 10:11:13
举报
文章被收录于专栏:波波烤鸭波波烤鸭

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

一、缓存中的重要概念

注解

说明

Cache

缓存接口,定义缓存操作。实现有:RedisCache、EhcacheCache、ConcurrentMapCache等

CacheManager

缓存管理器,管理各种缓存组件

@Cacheable

注意针对方法配置,能够根据方法的请求参数对其进行缓存

@CacheEvict

清空缓存

@CachePut

保证方法被调用,又希望结果被缓存。与@Cacheable区别在于是否每次都调用方法,常用于更新

@EnableCaching

开启基于注解的缓存

keyGenerator

缓存数据时key生成策略

serialize

缓存数据时value序列化策略

@CacheConfig

统一配置类的缓存注解属性

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

属性

说明

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:@Cacheable(value=”mycache”) 或者@Cacheable(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如:@Cacheable(value=”testcache”,key=”#id”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存/清除缓存例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)

unless

否定缓存。当条件结果为TRUE时,就不会缓存@Cacheable(value=”testcache”,unless=”#userName.length()>2”)

allEntries (@CacheEvict )

是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 例如: @CachEvict(value=”testcache”,allEntries=true)

beforeInvocation(@CacheEvict)

是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存例如:@CachEvict(value=”testcache”,beforeInvocation=true)

二、SpEL上下文数据

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

名称

位置

描述

示例

methodName

root对象

当前被调用的方法名

#root.methodname

method

root对象

当前被调用的方法

#root.method.name

target

root对象

当前被调用的目标对象实例

#root.target

targetClass

root对象

当前被调用的目标对象的类

#root.targetClass

args

root对象

当前被调用的方法的参数列表

#root.args[0]

caches

root对象

当前方法调用使用的缓存列表

#root.caches[0].name

Argument Name

执行上下文

当前被调用的方法的参数,如findArtisan(Artisan artisan),可以通过#artsian.id获得参数

#artsian.id

result

执行上下文

方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false)

#result

注意

  1. 当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。 如   @Cacheable(key = “targetClass + methodName +#p0”)
  2. 使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。 如:   @Cacheable(value=“users”, key="#id")   @Cacheable(value=“users”, key="#p0")

三、SpringCache的使用

1.导入依赖

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

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

在这里插入图片描述
在这里插入图片描述

3.创建业务类

代码语言:javascript
复制
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接口,并实现相关的方法

代码语言:javascript
复制
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.配置缓存管理器

在这里插入图片描述
在这里插入图片描述

Spring的配置文件中如下配置

在这里插入图片描述
在这里插入图片描述

6.测试代码

代码语言:javascript
复制
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");
    }

}

测试结果

代码语言:javascript
复制
第一次查询...
执行了缓存查询...没有命中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

搞定

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-11-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、缓存中的重要概念
  • 二、SpEL上下文数据
  • 三、SpringCache的使用
    • 1.导入依赖
      • 2.然后在启动类注解@EnableCaching开启缓存
        • 3.创建业务类
          • 4.创建缓存实现类
            • 5.配置缓存管理器
              • 6.测试代码
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档