qinfengge

qinfengge

醉后不知天在水,满船清梦压星河
github
email
telegram

spring boot中的缓存

缓存通常用来加快数据库中经常要使用的数据。大部分情况下我们使用 redis 来缓存 MySQL 数据库的热点数据。

EnableCaching#

在 spring boot 中使用缓存还是比较简单的
首先添加依赖

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

在启动类开启缓存支持

@SpringBootApplication
@EnableCaching

在配置文件中指定使用 redis 缓存,如果不指定则使用 jvm 内存
在使用 redis 做缓存之前,需要正确的配置 redis 的连接信息

#cacheing
spring.cache.type=redis
#指定前缀
#spring.cache.redis.key-prefix=test
#指定存活时长
#spring.cache.redis.time-to-live= 1d

最后在 redis 的配置类中增加 @EnableCaching 注解和 缓存管理器

/**
     * 申明缓存管理器,会创建一个切面(aspect)并触发Spring缓存注解的切点(pointcut)
     * 根据类或者方法所使用的注解以及缓存的状态,这个切面会从缓存中获取数据,将数据添加到缓存之中或者从缓存中移除某个值
     *
     * @return
     */
    @Bean
    @SuppressWarnings("all")
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        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.ofDays(1))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

        return RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
    }

缓存注解#

缓存注解解释
@EnableCaching开启缓存注解的支持
@CacheConfig用于统一制定一些配置参数,这样在其他缓存注解里面就不用重复指定
@Cacheable如果之前已经有缓存数据值直接返回缓存数据,否则执行方法,缓存方法的返回结果
@CachePut能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用
@CacheEvict能够根据一定的条件对缓存进行清空
@Caching组合多个 Cache 注解的使用

@CacheConfig#

此注解常用来配置统一的缓存参数

// 在controller中使用此注解用来指定缓存的名字,类似于前缀
@CacheConfig(cacheNames = "test")

@Cacheable#

此注解常用于查询方法中,使用此注解后会先从缓存中查,如果缓存中没有,再从数据库中查,并把查询出的结果放入缓存中。

Mermaid Loading...

image

// 如果配置了@CacheConfig的全局cacheName/value 则这里面的可以省略
@Cacheable(value = "test", key = "methodName")
// @Cacheable支持el表达式
@Cacheable(key = "methodName + ':' + #p0 + ':' + #p1")
public Result<Object> getSubordinateAddress(String province,String city){}
@Cacheable(value="users", key="#user.id")
public User find(User user) {}

key 支持的属性列表如下

属性名称描述示例
methodName当前方法名#root.methodName
method当前方法#root.method.name
target当前被调用的对象#root.target
targetClass当前被调用的对象的 class#root.targetClass
args当前方法参数组成的数组#root.args[0]
caches当前被调用的方法使用的 Cache#root.caches[0].name

@CachePut#

此注解常用来更新缓存。它会忽略缓存中的值,而是始终执行方法。
执行顺序为 调用方法 ---> 获取结果 ---> 更新缓存

Mermaid Loading...
@CachePut(value = "myCache", key = "#entity.id")
    public void saveEntity(MyEntity entity) {
        repository.save(entity);
    }

@CacheEvict#

此注解用来删除对应的缓存。

image

@CacheEvict(value = "myCache", key = "#id")
    public void deleteEntityById(Long id) {
        repository.deleteById(id);
    }

在使用 allEntries=true 时,会忽略 key,删除指定 cacheName/value 中的全部值。
你也可以使用 cacheMange 对象来删除指定的缓存,以下代码表示当 test 缓存不为空时,将其清空

Objects.requireNonNull(restTemplateConfig.cacheManager(null).getCache("test")).clear();

@Caching#

此注解用来组合多个上面的缓存注解进行使用

image

@Caching(
        cacheable = {
            @Cacheable(value = "myCache", key = "#id")
        },
        evict = {
            @CacheEvict(value = "otherCache", key = "#id")
        }
    )
    public MyEntity getEntityById(Long id) {
        return repository.findById(id).orElse(null);
    }

调用顺序如下

Mermaid Loading...

SpringBoot 项目中使用缓存 Cache 的正确姿势!!!
SpringBoot 缓存管理 @EnableCaching、@Cacheable

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。