一、准备操作
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)、读多写多,直接操作数据库