spring-cache的使用

一、准备操作

1.1、引入依赖

<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>

1.2、添加application.properties配置

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.cache.type=redis
#过期时间,单位:毫秒
spring.cache.redis.time-to-live=3600000
#缓存前缀
#spring.cache.redis.key-prefix=CACHE_
#是否启用前缀,默认启用:true
spring.cache.redis.use-key-prefix=true
#是否存储空值,可用来防止缓存穿透
spring.cache.redis.cache-null-values=true

1.3、启动类上开启缓存注解@EnableCaching

@EnableCaching
@MapperScan("com.isyoubao.gulimall.product.dao")
@EnableFeignClients("com.isyoubao.gulimall.product.fegin")//开启服务远程调用,并指定远程调用接口
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallProductApplication {
	...
}

1.4、添加Config配置器

@EnableConfigurationProperties(CacheProperties.class)
@Configuration
@EnableCaching
public class MyCacheConfig {

    /**
     * spring-cache默认保存到redis中的数据是序列化之后的字节流,
     * 为保证数据的可观赏性和跨平台性,这里做配置改为json格式
     * @return
     */
    @Bean
    RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){
        //获取RedisCache的默认配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        //设置缓存格式
        config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        //获取spring中绑定的redis配置
        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;
    }
}

二、开始使用

@Cacheable:插入缓存,查询缓存,有数据直接返回不调用方法,无缓存查询数据库,并将返回值进行缓存
@CacheEvict:删除缓存,执行方法之后,将redis中的指定缓存进行清空,常用于修改数据之后
@CachePut:更新缓存,执行修改操作之后,将缓存中的数据进行删除并更新(未加锁,高并发存在脏读)
@Caching:多任务执行,可一次执行上方多个任务

2.1、@Cacheable

使用如下:

/*
 *	@Cacheable({"category"})
 *      代表当前方法的结果需要缓存,如果缓存中有,则不执行方法
 *      缓存中没有,执行方法,将结果进行缓存
 * 	value:缓存时需要指定一个或多个key作为分区(数组)
 * 	key:保存的key名称。是一个表达式:root.methodName可获取当前方法名称,
 * 		直接写字符串的话需要加单引号,如:key="'getLevel1Categorys'"
 */
@Cacheable(value = {"category"},key = "#root.methodName")
@Override
public List<CategoryEntity> getLevel1Categorys() {
    List<CategoryEntity> entityList = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", "0"));
    return entityList;
}

2.2@CacheEvict和@Caching

使用如下:

	/*
     * 删除节点:
     *      1)、删除单个:删除指定key
     *              @CacheEvict(value = {"category"},key = "'getLevel1Categorys'")
     *      2)、删除多个:以添加多个任务方式进行删除
 	 *                  @Caching(evict = {
 	 *                      @CacheEvict(value = {},key="''"),
 	 *                      @CacheEvict(value = {},key="''"),
 	 *                  })
     *      3)、删除多个:allEntries = true(按分组节点删除)
     *              @CacheEvict(value = {"category"},allEntries = true)
     * @param category
     */
//    @CacheEvict(value = {"category"},key = "'getLevel1Categorys'")
//    @Caching(evict = {
//            @CacheEvict(value = {"category"},key = "'getLevel1Categorys'"),
//            @CacheEvict(value = {"category"},key = "'getcatalogJson'"),
//    })
@CacheEvict(value = {"category"},allEntries = true)
@Transactional
@Override
public void updateDetail(CategoryEntity category) {
    baseMapper.updateById(category);
    if (StringUtils.isNotEmpty(category.getName())){
        relationService.updateCategory(category.getName(),category.getCatId());
    }
}

三、特点

     * 1、每一个需要缓存的数据都需要指定一个名称,将数据缓存进去
     * 2@Cacheable({"category"})
     *      代表当前方法的结果需要缓存,如果缓存中有,则不执行方法
     *      缓存中没有,执行方法,将结果进行缓存
     * 3、默认行为
     *      1)、如果缓存中有,方法不调用
     *      2)、key默认自动生成,缓存的名字::SimpleKey [](自动生成的key)
     *      3)、缓存的value值,默认使用jdk序列化机制,将序列化后的数据存到redis
     *      4)、默认ttl时间,-1(永久)
     *
     *    自定义:
     *      1)、指定生成的缓存使用的key:   key属性指定,接受一个数组
     *      2)、指定缓存的数据的存活时间:   配置文件中修改ttl
     *      3)、将格式转为json(跨平台):	config配置类中配置
     * 4、spring-cache的不足:
     *      1)、读模式:
     *          缓存穿透:查询一个null数据。解决:存储一个null数据 spring.cache.redis.cache-null-values=true
     *          缓存击穿:大量查询一个刚过期的数据。解决:cache没有配置解决方案,需要手上加锁,且是本机锁,不是分布锁,但也不影响
     *          缓存雪崩:访问频率较高且一次大量数据同时过期,导致全部查库。解决:加上过期时间和随机过期时间:spring.cache.redis.time-to-live=3600000
     *      2)、写模式:
     *          1)、读写加锁
     *          2)、引入Canal,感知Mysql数据变动自动更新
     *          3)、读多写多,直接操作数据库
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值