SpringCache完整案例介绍

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


一、缓存中的重要概念

SpringCache完整案例介绍


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

SpringCache完整案例介绍


二、SpEL上下文数据


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

SpringCache完整案例介绍


注意:


当我们要使用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开启缓存


SpringCache完整案例介绍


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.配置缓存管理器

SpringCache完整案例介绍


Spring的配置文件中如下配置


SpringCache完整案例介绍

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


搞定~


上一篇:VMware网络模式分析


下一篇:高频交易策略之Penny Jump