SpringCache 整合 Redis
1.配置
spring.cache.type=redis
@EnableCaching
@EnableFeignClients(basePackages = "com.cwh.gulimall.product.feign")
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallProductApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallProductApplication.class, args);
}
}
2.使用
// 需要指定放入哪个名字的缓存(分区)
@Cacheable({"category"}) // 代表当前方法的结果需要缓存,如果缓存中有,不用调用方法;如果缓存中没有,调用方法后将结果放入缓存
@Override
public List<CategoryEntity> getLevel1Categories() {
return list(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0));
}
3.@Cacheable细节设置
1.缓存到Redis中数据具有如下的特点:
- 如果缓存中有,方法不会被调用;
- key默认自动生成;形式为"缓存的名字::SimpleKey ";
- 缓存的value值,默认使用jdk序列化机制,将序列化后的数据缓存到redis;
- 默认ttl时间为-1,表示永不
2.然而这些并不能够满足我们的需要,我们希望:
- 能够指定生成缓存所使用的key;
- 指定缓存的数据的存活时间;
- 将缓存的数据保存为json形式
针对于第一点,使用@Cacheable注解的时候,设置key属性,接受一个SpEL(Spring Expression Language):
@Cacheable(value = {"category"},key = "'level1Categorys'")
针对于第二点,在配置文件中指定ttl:
cache:
type: redis
redis:
time-to-live: 3600000
// 需要指定放入哪个名字的缓存(分区)
@Cacheable(value = {"category"},key = "#root.method.name") // 代表当前方法的结果需要缓存,如果缓存中有,不用调用方法;如果缓存中没有,调用方法后将结果放入缓存
@Override
public List<CategoryEntity> getLevel1Categories() {
return list(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0));
}
@Cacheable(value = {"category"},key = "#root.methodName")
@Override
public Map<String, List<Catelog2Vo>> getCatalogJson() {
/**
* 优化循环查库
*/
List<CategoryEntity> list = this.list();
// 1.查出所有1级分类
List<CategoryEntity> level1List = getParentCid(list, 0L);
// 2.封装数据
Map<String, List<Catelog2Vo>> parentCid = level1List.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
// 2.1.查到该一级分类的二级分类
List<CategoryEntity> level2List = getParentCid(list, v.getCatId());
List<Catelog2Vo> catelog2Vos = null;
if (level2List != null) {
catelog2Vos = level2List.stream().map(c2 -> {
Catelog2Vo catelog2Vo = new Catelog2Vo(v.getCatId().toString(), null, c2.getCatId().toString(), c2.getName());
// 2.2.查到该二级分类对应的三级分类,并封装为vo
List<Catelog2Vo.Catelog3Vo> catelog3List = getParentCid(list, c2.getCatId())
.stream()
.map(c3 -> new Catelog2Vo.Catelog3Vo(
catelog2Vo.getId(),
c3.getCatId().toString(),
c3.getName())
).collect(Collectors.toList());
catelog2Vo.setCatalog3List(catelog3List);
return catelog2Vo;
}).collect(Collectors.toList());
}
return catelog2Vos;
}));
return parentCid;
}
4.自定义缓存配置------如何将数据以JSON的形式缓存到Redis
-
这涉及到修改缓存管理器的设置,CacheAutoConfiguration导入了RedisCacheConfiguration,而RedisCacheConfiguration中自动配置了缓存管理器RedisCacheManager,而RedisCacheManager要初始化所有的缓存,每个缓存决定使用什么样的配置,如果RedisCacheConfiguration有就用已有的,没有就用默认配置。
-
想要修改缓存的配置,只需要给容器中放一个"redisCacheConfiguration"即可,这样就会应用到当前RedisCacheManager管理的所有缓存分区中。
package com.cwh.gulimall.product.config;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;@EnableConfigurationProperties(CacheProperties.class)
@Configuration
@EnableCaching
public class MyCacheConfig {
/**
* 配置文件中的东西没有用到
* 1、原来和配置文件绑定的配置类是这样的
* @ConfigurationProperties(prefix="spring.cache")
* public class CacheProperties
* 2、让他生效
* @EnableConfigurationProperties(CacheProperties.class)
* @return
*/
@Bean
RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); // 在Redis中放入自动配置类,设置JSON序列化机制 config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); // 将配置文件中的所有配置都生效 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.type=redis
#设置超时时间,默认是毫秒
spring.cache.redis.time-to-live=3600000
#设置Key的前缀,如果指定了前缀,则使用我们定义的前缀,否则使用缓存的名字作为前缀
spring.cache.redis.key-prefix=CACHE_
spring.cache.redis.use-key-prefix=true
#是否缓存空值,防止缓存穿透
spring.cache.redis.cache-null-values=true
5.@CacheEvict
/**
* 级联更新,保证冗余字段一致
* @CacheEvict:失效模式
* 1.同时进行多种缓存操作 @Caching
* 2.指定删除某个分区下的所有数据 @CacheEvict(value = "category", allEntries = true)
* 3.存储同一类型的数据,都可以指定同一分区(缓存默认前缀:分区名)
* @param category
*/
// @CachePut 双写模式
// @CacheEvict(value = "category", allEntries = true)
@Caching(evict = {
@CacheEvict(value = "category", key = "'getLevel1Categories'"),
@CacheEvict(value = "category", key = "'getCatalogJson'")
})
@Transactional
@Override
public void updateCascade(CategoryEntity category) {
this.updateById(category);
if(!StringUtils.isEmpty(category.getName())){
// 保证冗余数据一致
categoryBrandRelationService.updateCategory(category.getCatId(), category.getName());
// TODO 其他数据一致
}
}