首页 > 数据库 >@Cacheable注解实现Redis缓存

@Cacheable注解实现Redis缓存

时间:2022-11-04 12:14:21浏览次数:81  
标签:缓存 Redis redis springframework Cacheable key spring org

SpringBoot 缓存之 @Cacheable 介绍

简介

介绍:

Spring 从 3.1 开始就引入了对 Cache 的支持。定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术。并支持使用 JCache(JSR-107)注解简化我们的开发。

其使用方法和原理都类似于 Spring 对事务管理的支持。Spring Cache 是作用在方法上的,其核心思想是,当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存在缓存中。

Cache 和 CacheManager 接口说明:

Cache 接口包含缓存的各种操作集合,你操作缓存就是通过这个接口来操作的。

Cache 接口下 Spring 提供了各种 xxxCache 的实现,比如:RedisCache、EhCache、ConcurrentMapCache

CacheManager 定义了创建、配置、获取、管理和控制多个唯一命名的 Cache。这些 Cache 存在于 CacheManager 的上下文中。

每次调用需要缓存功能的方法时,Spring 会检查指定参数的指定目标方法是否已经被调用过,如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。

@Cacheable 注解使用介绍

第一步:开启基于注解的缓存,使用 @EnableCaching 标注在 springboot 主启动类上

第二步:标注缓存注解

注:这里使用 @Cacheable 注解就可以将运行结果缓存,以后查询相同的数据,直接从缓存中取,不需要调用方法。

常用属性说明

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

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

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

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

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

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

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

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

  • key

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

  • keyGenerator

key 的生成器,可以自己指定 key 的生成器,通过这个生成器来生成 key。


这样放入缓存中的 key 的生成规则就按照你自定义的 keyGenerator 来生成。不过需要注意的是:@Cacheable 的属性,key 和 keyGenerator 使用的时候,一般二选一。

  • condition

符合条件的情况下才缓存。方法返回的数据要不要缓存,可以做一个动态判断。

  • unless

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

  • sync

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

  • spEL 编写 key

缓存的 key 支持使用 spEL 表达式去编写,下面总结一下使用 spEL 去编写 key 可以用的一些元数据:

@Cacheable注解实现Redis缓存

添加依赖

<!--集成redis -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.4.2</version>
</dependency>
<!-- redis依赖,2.0以上使用这个依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 缓存依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

配置文件中增加配置

####### Redis ################
#第几个数据库,由于redis中数据库不止一个
spring.redis.database=1
# 也可指定为127.0.0.1
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=88888888

# springboot2.x以上如此配置,由于2.x的客户端是lettuce
# 单位要带上
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.max-wait=10000ms
spring.redis.lettuce.shutdown-timeout=100ms

# springboot1.x如此配置,由于1.x的客户端是jedis
#spring.redis.jedis.pool.max-active=8
#spring.redis.jedis.pool.min-idle=0
#spring.redis.jedis.pool.max-idle=8
#spring.redis.jedis.pool.max-wait=-1
#spring.redis.timeout=500

实现自定义缓存管理器

package com.anson.config;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
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.*;

import java.time.Duration;

/**
 * @description: redis缓存配置类
 * @author: anson
 * @Date: 2019/12/8 21:34
 */

@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {

    private static final Logger logger = LoggerFactory.getLogger(RedisCacheConfig.class);

    // 自定义key生成器
    @Bean
    public KeyGenerator keyGenerator(){
        return (o, method, params) ->{
            StringBuilder sb = new StringBuilder();
            sb.append(o.getClass().getName()); // 类目
            sb.append(method.getName()); // 方法名
            for(Object param: params){
                sb.append(param.toString()); // 参数名
            }
            return sb.toString();
        };
    }

    // 配置缓存管理器
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(60000000)) // 60s缓存失效
                // 设置key的序列化方式
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
                // 设置value的序列化方式
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
                // 不缓存null值
                .disableCachingNullValues();

        RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();

        logger.info("自定义RedisCacheManager加载完成");
        return redisCacheManager;
    }


    // key键序列化方式
    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

    // value值序列化方式
    private GenericJackson2JsonRedisSerializer valueSerializer(){
        return new GenericJackson2JsonRedisSerializer();
       // return  new GenericFastJsonRedisSerializer();
    }
}

使用:可以直接使用了,在UserServiceImpl中

@Override
@Cacheable(cacheNames = "user" ,key="#id")
public User selectByPrimaryKey(Integer id){
    return  usermapper.selectByPrimaryKey(id);
}

@Override
@Cacheable(cacheNames = "users")
public List<User> getAll(){
    return usermapper.getAll();
}

其中,key如果不设置,会根据我们设置的生成器生成KEY

如果自己设置的话,有几种方式:

基本形式

@Cacheable(value="cacheName", key"#id")
public User method(int id);

组合形式

@Cacheable(value="cacheName", key"T(String).valueOf(#name).concat('-').concat(#password))
public User method(int name, String password);

对象形式

@Cacheable(value="cacheName", key"#user.id)
public User method(User user);

自定义Key生成器

@Cacheable(value="gomeo2oCache", keyGenerator = "keyGenerator")
public User method(User user);

测试

我们 打开druid的SQL监控,然后在swagger中进行操作,在Redis desktop manager中查看Redis,就可以看到第一次查询执行了数据库查询,并把结果存进了Redis中,以后执行同样的查询,在缓存没过期之前,都直接从Redis获取,不再执行数据库查询,可见Redis缓存成功运行和释放了数据库的压力了;


参考链接:
https://www.cnblogs.com/manmanblogs/p/15686332.html
https://blog.csdn.net/zl1zl2zl3/article/details/110987968

标签:缓存,Redis,redis,springframework,Cacheable,key,spring,org
From: https://www.cnblogs.com/2393920029-qq/p/16857298.html

相关文章

  • prometheus 监控案例-Tomcat、Redis、Mysql、Haproxy、Nginx
    服务监控  可以根据prometheus官网找到对应服务的exporter  https://prometheus.io/docs/instrumenting/exporters/监控Tomcat容器  基于第三方exporter实现......
  • redis 集群重启两种方式
    关闭集群:redis-cli-c-h192.168.10.137-p7000shutdown  redis-cli-c-h192.168.10.137-p7001shutdown  redis-cli-c-h192.168.10.137-p7002shutdo......
  • SpringCloud (五) - 云服务器Centos7.6,安装JDK,Maven,Mysql,Redis
    1、购买云服务器购买地址:https://cloud.tencent.com/act/pro/2022double11_warmup后面的环境都是基于此环境Centos7.6;2、安装SecureCRT和SecureFX2.1SecureCRT教......
  • 用Nodejs 实现一个简单的 Redis客户端
    目录0.写在前面1.背景映入2.数据库选择3.NodejsTCP连接3.代码编写4.实验5.wireshark抓包分析6.杂与代码0.写在前面大家如果有去看过nodejs所支持的官方库的......
  • redis Jedis
    packagecom.itheima.util;importredis.clients.jedis.Jedis;importredis.clients.jedis.JedisPool;importredis.clients.jedis.JedisPoolConfig;importjava.ut......
  • Redis 先操作数据库和先删除缓存, 一致性分析
    初始状态:数据库和缓存中v=10 第一种,先删除缓存在操作数据库:线程1准备更新数据库的值v=20,先删除缓存,此时线程2进来,缓存未命中,查询数据库v=10,写入缓存v=10,......
  • redis
    一、简介Redis与其他key-value缓存产品有以下三个特点:Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。Redis不仅仅支持简......
  • Redis Desktop Manager(Redis可视化工具)安装及使用教程
    1、https://blog.csdn.net/m0_55070913/article/details/123677891RedisDesktopManager(Redis可视化工具)安装及使用教程2、一、工具/材料官网下载:https://redisdesk......
  • Redis系列9:Geo 类型赋能亿级地图位置计算
    Redis系列1:深刻理解高性能Redis的本质Redis系列2:数据持久化提高可用性Redis系列3:高可用之主从架构Redis系列4:高可用之Sentinel(哨兵模式)Redis系列5:深入分析Cluster集......
  • Redisson 分布式锁实现之前置篇 → Redis 的发布/订阅 与 Lua
    开心一刻我找了个女朋友,挺丑的那一种,她也知道自己丑,平常都不好意思和我一块出门昨晚,我带她逛超市,听到有两个人在我们背后小声嘀咕:“看咱前面,想不到这么丑都有人要。......