SpringBoot 缓存之 @Cacheable介绍

目录

1 概述

2 @Cacheable注解使用详细介绍

        2.1 @Cacheable注解使用

        2.2  Cacheable 注解的属性


1 概述

        Spring高版本引入了cache的注解技术。该技术是一种规范。Redis的cache技术,底层使用的是Spring Data Redis。cache技术的使用需要掌握的有@EnableCaching、@Cacheable、@CacheEvict、@Caching、@CacheConfig注解的使用,这些注解支持SpringSPEL表达式方式。

今天先了解@Cacheable注解。

2 @Cacheable注解使用详细介绍

        2.1 @Cacheable注解使用

步骤一:cacheConfig配置类

package com.liubujun.redis_springboot.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: liubujun
 * @Date: 2022/2/5 15:21
 */

@Configuration
@EnableCaching
public class CacheConfig {

    /**
     * CacheManager为一个接口,RedisCacheManager为该接口的实现
     * redisConnectionFactory 连接工厂
     * cacheDefaults 默认配置
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){
        RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(defaultCacheConfig(10000))
                .withInitialCacheConfigurations(initCacheConfigMap())
                .transactionAware()
                .build();
        return redisCacheManager;

    }

    /**
     * 默认配置中进行了序列化的配置
     * @param second
     * @return
     */
    private RedisCacheConfiguration defaultCacheConfig(Integer second) {
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        //配置序列化 解决乱码的问题
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(second))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

    return config;

    }

    /**
     * 针对不同的redis的key 有不同的过期时间
     * @return
     */
    private Map initCacheConfigMap() {

        Map configMap = new HashMap<>();
        configMap.put("User",this.defaultCacheConfig(1000));
        configMap.put("User1",this.defaultCacheConfig(1000));
        configMap.put("User2",this.defaultCacheConfig(1000));
        configMap.put("User3",this.defaultCacheConfig(1000));
        return configMap;
    }

}

步骤二:application.properties文件配置redis的参数

#redis服务器地址(自己redis所在主机地址)
spring.redis.host=*******
#redis服务器连接端口
spring.redis.port=6379
#redis数据库索引(默认是0)
spring.redis.database=0
#连接超时时间
spring.redis.timeout=1800000
#连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=20
#最大阻塞等待时间(负数表示没有限制)
spring.redis.lettuce.pool.max-wait=-1
#连接池中最大空闲连接
spring.redis.lettuce.pool.max-idle=5
#连接池中最小空闲连接
spring.redis.lettuce.pool.min-idle=0

步骤三:测试类编写

package com.liubujun.redis_springboot.controller;

import com.liubujun.redis_springboot.entity.User;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @Author: liubujun
 * @Date: 2022/2/2 16:17
 */

@RestController
@RequestMapping("/redisTest")
public class TestController {
    
    @GetMapping("/cache/{id}")
    @Cacheable(cacheNames = "User",key = "#id") //此时缓存中的key为id,value为查询出来的数据(#id就表示取出参数id的值作为key)
    public User findUserById(@PathVariable("id") Integer id){
        User user = new User();
        user.setId(id);
        user.setName("测试:springBooth中Cache"+id+"查询时间戳"+System.currentTimeMillis());
        System.out.println("模拟数据库查询数据id:"+id+"name:"+user.getName());
        return user;
    }
}

步骤四:浏览器访问

相同id连续两次访问接口

SpringBoot 缓存之 @Cacheable介绍_第1张图片

 

控制台只有一句输出语句: 

SpringBoot 缓存之 @Cacheable介绍_第2张图片

 

 redis客户端中存储的值:

SpringBoot 缓存之 @Cacheable介绍_第3张图片

 

我将用相同的id连续访问两次,控制台只有一句输出语句,那么就说明:第一次访问走了代码逻辑并且将返回结果放入了cacheable中。第二次直接从缓存中取出的数据,没有走代码逻辑。体检了cacheable的作用。

总结: @Cacheable 注解可以将运行结果缓存,以后查询相同的数据,直接从缓存中调取,不需要调用方法,换言之:在方法上加了@Cacheable 注解后,每次调用该方法,都会先检查缓存中有没有相同的key,如果有直接从缓存中获取,没有再调用具体代码逻辑。

        2.2  Cacheable 注解的属性

  • cacheNames/value :用来指定缓存组件的名字

  • key :缓存数据时使用的 key,可以用它来指定。默认是使用方法参数的值。(这个 key 你可以使用 spEL 表达式来编写)

  • keyGenerator :key 的生成器。 key 和 keyGenerator 二选一使用

  • cacheManager :可以用来指定缓存管理器。从哪个缓存管理器里面获取缓存。

  • condition :可以用来指定符合条件的情况下才缓存

  • unless :否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。当然你也可以获取到结果进行判断。(通过 #result 获取方法结果)

  • sync :是否使用异步模式。

1)cacheNames/value :

用来指定缓存组件的名字,将方法的返回结果放在哪个缓存中,可以是数组的方式

@GetMapping("/cache/{id}")
@Cacheable(cacheNames = "User") //也可以这样写@Cacheable(cacheNames {"User","Users"})
public User findUserByIds(@PathVariable("id") Integer id){
    User user = new User();
    user.setId(id);
    user.setName("测试:springBooth中Cache"+id+"查询时间戳"+System.currentTimeMillis());
    System.out.println("模拟数据库查询数据id:"+id+"name:"+user.getName());
    return user;
}

2)key :

缓存数据时使用的key。默认使用的是方法参数的值,也可以使用spEL表达式编写

@GetMapping("/cache/{id}")
@Cacheable(cacheNames = "User",key = "#root.methodName+'[' + #id + ']'") //这时如果传入的id为500,那么key=findUserById[500]
public User findUserById(@PathVariable("id") Integer id){
    User user = new User();
    return user;
}

3)keyGenerator :

key的生成器,可以用自己指定的生成器去生成key

4)condition :

符合条件的情况下才进行缓存

@GetMapping("/cache/{id}")
@Cacheable(cacheNames = "User",condition = "#id >1 ") //这里表示id值大于1时才进行缓存
public User findUserByIds(@PathVariable("id") Integer id){
    User user = new User();
    return user;
}

5)unless :

否定缓存,当unless指定的条件为true时,方法的返回值不会被缓存

@GetMapping("/cache/{id}")
@Cacheable(cacheNames = "User",unless = "#id >1 ") //这里表示id值大于1时不会进行缓存
public User findUserByIds(@PathVariable("id") Integer id){
    User user = new User();
    return user;
}

6)sync :

是否使用异步模式,默认是方法执行完后,以同步的方式将方法返回的结果存在缓存中

参考博客:SpringBoot 缓存之 @Cacheable 详细介绍_勇往直前的专栏-CSDN博客_@cacheable

你可能感兴趣的:(spring,boot,缓存,spring)