SpringCache

为什么使用缓存:在某些数据不频繁改变的情况下,我们没有必要每次读取数据都读取数据库,我们可以使用缓存的方式,springcache就是springboot中的一个缓存框架
1.引入依赖


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

2.开启缓存

在启动类上添加 @EnableCaching

3.添加缓存注解

@Cacheable(value="cataloge",key="'cataloge'") 表明该方法的返回值会被缓存下来下次调用该方法时会先检查是否有缓存,常用在查询方法前,传入的参数value为缓存的名字(类似于分区),推荐按照业务类型分,key是缓存的名字,注意字符串要加上''否则会认为是表达式

4.删除缓存(失效模式)

@CacheEvict(value="cataloge",key="'cataloge'") 删除指定的缓存,常用在删除方法前,注意字符串要加上''否则会认为是表达式
@CacheEvict(value="cataloge",allEntries=true) 删除分区中所有数据

组合多个操作

@Caching(evict={@CacheEvict(value="cataloge",key="'cataloge'"),@CacheEvict(value="cataloge",key="'cataloge2'")})

5.更新缓存(双写模式)

@CachePut(value="cataloge",key="'cataloge'") 把方法的返回值更新到缓存中,注意字符串要加上''否则会认为是表达式

这里需要注意的是,SpringCache默认使用的是ConcurrentHashMap,它不会自动回收key,所以如果使用默认的这个缓存,程序就会越来越大,并且得不到回收。最终可能导致OOM。

当然我们也可以使用别的缓存框架,如果我们引入的是spring-data-redis,只需要编写配置文件,就会指定redis作为我们的缓存实现

spring.cache.type=redis

6.自定义缓存配置
SpringCache默认配置中,缓存的value值使用jdk序列化机制生成,且缓存时间为永不过期,这不符合我们要求(缓存永不过期的话一旦缓存与数据库不一致很难得到修正),我们可以自定义缓存配置

@EnableConfigurationProperties(CacheProperties.class)
@Configuration
public class MyCacheConfig{
    //这里以redis作为缓存的情况下为例
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();

        //每次修改配置后都会返回一个新对象
        config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); //value改成json序列化方式
        
        CacheProperties.Redis redisProperties = cacheProperties.getRedis();
        //将配置文件中所有的配置都生效
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixKeysWith(redisProperties.getKeyPrefix());
        }
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }
        return config;
        
        
    }

}

spring.cache.redis.time-to-live=3600000;  //设置ttl,单位ms
spring.cache.redis.cache-null-value=true; //缓存空值,防止缓存穿透

不足之处:
缓存的三大问题,我们来看下SpringCache有没有很好的解决
缓存穿透:热点数据缓存过期,大量请求涌入数据库。解决:加锁,SprngCache默认是不加锁的,我们可以在@Cacheable中指定sync=true 加锁(虽然加的是本地锁但已经够用了)
缓存击穿:大量查询请求查询一个缓存中没有的数据。 解决:缓存空值
缓存雪崩:大量缓存同时过期。解决:随机过期时间。由于我们业务缓存放入时间不同,因此不太可能在同一时间过期。

posted @ 2021-04-29 22:05  刚刚好。  阅读(276)  评论(0)    收藏  举报