SpringCache使用

SpringCache使用

1.引入依赖

引入springcache依赖

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

使用的是redis缓存,也要引入redis缓存

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <exclusions>
    <exclusion>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    </exclusion>
    </exclusions>
</dependency>

为什么去除lettuce,参考《分布式缓存》,引入redisson控制

2.写配置

(1)自动配置用了哪些类?

CacheAutoConfiguration会导入RedisCacheConfiguration然后自动配置
RedisChacheManager

因为源码自动配置了

static class CacheConfigurationImportSelector implements ImportSelector {

		@Override
		public String[] selectImports(AnnotationMetadata importingClassMetadata) {
			CacheType[] types = CacheType.values();
			String[] imports = new String[types.length];
			for (int i = 0; i < types.length; i++) {
				imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
			}
			return imports;
		}
	}

3.测试使用缓存

开启缓存

@EnableCaching //开启缓存
public class GulidemoProductApplication {
    public static void main(String[] args) {
        SpringApplication.run (GulidemoProductApplication.class, args);
    }

}
@Cacheable 触发把一个数据保存到缓存里面
@CacheEvict 触发将缓存删除的操作
@CachePut 不影响方法执行更新缓存
@Caching 组合以上多个操作
@CacheConfig 在类级别上既同一个类上共享缓存的配置

在这里插入图片描述

 //指定缓存的名称,可以用来分区,按业务类型分区
    @Cacheable("ategorys")//代表当前方法需要缓存,如果缓存中有、该方法不会被调用。如果缓存没有,执行完方法后结果会缓存进缓存
    

设置redis自动配置

自动配置源码

CacheAutoConfiguration

// 缓存自动配置源码
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
                     HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
@Import({ CacheConfigurationImportSelector.class, // 看导入什么CacheConfiguration
         CacheManagerEntityManagerFactoryDependsOnPostProcessor.class })
public class CacheAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {
        return new CacheManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
    }

    @Bean
    public CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties cacheProperties,
                                                                 ObjectProvider<CacheManager> cacheManager) {
        return new CacheManagerValidator(cacheProperties, cacheManager);
    }

    @ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
    @ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
    static class CacheManagerEntityManagerFactoryDependsOnPostProcessor
        extends EntityManagerFactoryDependsOnPostProcessor {

        CacheManagerEntityManagerFactoryDependsOnPostProcessor() {
            super("cacheManager");
        }

    }

RedisCacheConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisConnectionFactory.class)
@AutoConfigureAfter(RedisAutoConfiguration.class)
@ConditionalOnBean(RedisConnectionFactory.class)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class RedisCacheConfiguration {

    @Bean // 放入缓存管理器
    RedisCacheManager cacheManager(CacheProperties cacheProperties, 
                                   CacheManagerCustomizers cacheManagerCustomizers,
                                   ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
                                   ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers,
                                   RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
        RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(
            determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
        List<String> cacheNames = cacheProperties.getCacheNames();
        if (!cacheNames.isEmpty()) {
            builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
        }
        redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
        return cacheManagerCustomizers.customize(builder.build());
    }

配置

/**
 * @author qxb
 * @version 0.0.3
 * @description MyCacheConfig
 * @since 2021/6/9 23:28
 */
//EnableConfigurationProperties 将不入spring容器的配置加载入容器
@EnableConfigurationProperties(CacheProperties.class)
@EnableCaching
@Configuration
public class MyCacheConfig {

    //读取EnableConfigurationProperties加载入容器的配置也可以在方法参数上传入使用如 redisCacheConfiguration(CacheProperties cacheProperties)
    @Autowired
    CacheProperties cacheProperties;

    /*设置自定义redis缓存配置入spring容器*/
    @Bean
    RedisCacheConfiguration redisCacheConfiguration(){
        //设置默认配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig ();
        config = config.serializeKeysWith (RedisSerializationContext.SerializationPair.fromSerializer (new StringRedisSerializer ()));
        config = config.serializeValuesWith (RedisSerializationContext.SerializationPair.fromSerializer (new GenericJackson2JsonRedisSerializer ()));

        //读取配置文件内的配置,取自RedisCacheConfiguration
        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;
    }
}

删除缓存

  //简单用法
  @CacheEvict(value = {"categorys"},key = "'getLevel1Categorys'")
    
    
    //调用该方法会删除缓存category下的所有cache,如果要删除某个具体,用key="''"
@Override
@CacheEvict(value = {"category"},allEntries = true)

如果要清空多个缓存,用@Caching(evict={@CacheEvict(value="")})

SpringCache的不足

1)、读模式

缓存穿透:查询一个null数据。解决方案:缓存空数据,可通过spring.cache.redis.cache-null-values=true
缓存击穿:大量并发进来同时查询一个正好过期的数据。解决方案:加锁 ? 默认是无加锁的;
使用sync = true来解决击穿问题
@Cacheable(value = {"categorys"},key = "#root.method.name",sync = true)

缓存雪崩:大量的key同时过期。解决:加随机时间。
spring.cache.redis.time-to-live=3600000

2)、写模式:(缓存与数据库一致)

读写加锁。
引入Canal,感知到MySQL的更新去更新Redis
读多写多,直接去数据库查询就行
3)、总结:

常规数据(读多写少,即时性,一致性要求不高的数据,完全可以使用Spring-Cache):

写模式(只要缓存的数据有过期时间就足够了)

特殊数据:特殊设计

缓存雪崩:大量的key同时过期。解决:加随机时间。
spring.cache.redis.time-to-live=3600000

2)、写模式:(缓存与数据库一致)

读写加锁。
引入Canal,感知到MySQL的更新去更新Redis
读多写多,直接去数据库查询就行
3)、总结:

常规数据(读多写少,即时性,一致性要求不高的数据,完全可以使用Spring-Cache):

写模式(只要缓存的数据有过期时间就足够了)

特殊数据:特殊设计


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值