1.引入依赖
pom.xml增加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
2.写配置文件
? a.引入后自动配置?
? CacheAutoConfiguration 会导入RedisCacheConfiguration 自动配置好了管理器 RedisCacheManager
? b. 初始化缓存配置
【思路】 最终配置文件在最后步骤
spring.cache.type=redis
spring.redis.host=192.168.31.125
spring.redis.password=
spring.redis.port=6379
3.测试使用缓存
【—>】@Cacheable :触发将数据保存到缓存的操作
【—>】@CacheEvict: 触发将数据从缓存删除的操作
【—>】@CachePut: 不影响方法执行更新缓存
【—>】@Caching: 组合操作缓存
【—>】@CacheConfig: 在类级别(相同的类)上共享缓存配置
? a.开启缓存 @EnableCaching
【思路】
@EnableCaching
@SpringBootApplication
public class GulimallProductApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallProductApplication.class, args);
}
}
? b.只需要注解就能开启缓存操作
【思路】@Cacheable :触发将数据保存到缓存的操作
【—>】@Cacheable({“category”})
调用数据 有缓存读取缓存并且方法不会被调用。 没有缓存就先写入缓存
保存一级菜单
@Cacheable({"category"})
@Override
public List<CategoryEntity> getLevel1Categorys() {
System.out.println("调用方法查询一级分类了");
return baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid",0));
}
保存二级菜单
@Cacheable(value = {"category"},key="#root.methodName")
@Override
public Map<String, List<Catelog2Vo>> getCatalogJson() {
System.out.println("进入了查数据库逻辑");
List<CategoryEntity> selectList = baseMapper.selectList(null);
List<CategoryEntity> level1Categorys = getParent_cid(selectList, 0L);
Map<String, List<Catelog2Vo>> collect = level1Categorys.stream().collect(Collectors.toMap(k -> {
return k.getCatId().toString();
}, v -> {
List<CategoryEntity> categoryEntities = getParent_cid(selectList, v.getCatId());
List<Catelog2Vo> catelog2Vos = null;
if (categoryEntities != null) {
catelog2Vos = categoryEntities.stream().map(level2 -> {
List<CategoryEntity> levl3Catelog = getParent_cid(selectList, level2.getCatId());
List<Catelog2Vo.Catelog3Vo> catelog3VoList = null;
if (levl3Catelog != null) {
catelog3VoList = levl3Catelog.stream().map(level3 -> {
new Catelog2Vo.Catelog3Vo("", "", "");
Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo(
level2.getCatId().toString(),
level3.getCatId().toString(),
level3.getName()
);
return catelog3Vo;
}).collect(Collectors.toList());
}
Catelog2Vo catelog2Vo = new Catelog2Vo(
v.getCatId().toString(),
catelog3VoList,
level2.getCatId().toString(),
level2.getName()
);
return catelog2Vo;
}).collect(Collectors.toList());
}
return catelog2Vos;
}));
return collect;
}
默认行为:
? 缓存汇总有结果 这个备注接的方法就不会被调用了
缓存key自动生成 缓存名字: ::SimpleKey
? 缓存value值 默认使用jdk的序列化机制 将序列化后的数据存入redis
? 默认时间 -1 不过期
自定义:
1) 指定的生成缓存的key @Cacheable key接收的是表达式 key="‘someRedisKey’" 或者用方法名key="#root.method.name"
2) 指定缓存的过期时间 配置文件修改 spring.cache.redis.time-to-live=60000 单位ms
3) 数据保存为json格式
【思路】
修改配置方法:
@EnableCaching
@Configuration
public class MyCacheConfig {
@Bean
RedisCacheConfiguration redisCacheConfiguration(){
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
System.out.println("执行Cache的配置类");
config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return config;
}
}
会导致配置文件失效 如下处理 原因如下代码展示: 注意那个return this.redisCacheConfiguration;
【思路】
if (this.redisCacheConfiguration != null) {
return this.redisCacheConfiguration;
}
Redis redisProperties = this.cacheProperties.getRedis();
org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
.defaultCacheConfig();
config = config.serializeValuesWith(SerializationPair
.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
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;
代码指出,如果走了配置类 那么底下的几个if 就没有进行 我们把下面的几个信息需要重新写进配置类
原先的配置类样子:
【思路】
@ConfigurationProperties(prefix = "spring.cache")
public class CacheProperties {
...
给配置类加入注解 修改配置类
最终配置类
@EnableConfigurationProperties(CacheProperties.class)
@EnableCaching
@Configuration
public class MyCacheConfig {
@Bean
RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
System.out.println("执行Cache的配置类");
config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
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;
}
}
4.配置原理
? CacheAutoConfiguration
-> RedisCacheConfiguration
-> 自动配置 RedisCacheMannager
->初始化所有的缓存
-> 每个缓存决定配置【RedisCacheConfiguration 有:就有 无:用默认】
? 修改缓存配置 需要给容器 放置一个RedisCacheConfiguration
-> 应用当前RedisCacheMannager 管理的所有缓存分区
最终的配置文件
redis.properties
spring.cache.type=redis
spring.redis.host=192.168.31.125
spring.redis.password=
spring.redis.port=6379
spring.cache.redis.time-to-live=180000
#spring.cache.redis.key-prefix=CACHE_
#spring.cache.redis.use-key-prefix=true
#是否缓存控制 解决缓存穿透问题
spring.cache.redis.cache-null-values=true
验证注解的修改数据:
【思路】
【—>】 @CacheEvict(value = {“category”},key="‘getLevel1Categorys’")
更新数据时 调用清除缓存 (读取时候 发现缓存为空 为给与填充)
@CacheEvict(value = {"category"},key="'getLevel1Categorys'")
@Transactional
@Override
public void updateCascade(CategoryEntity category) {
this.updateById(category);
categoryBrandRelationService.updateCategory(category.getCatId(),category.getName());
}
【—>】@Caching: 组合操作演示
@Caching(evict = {
@CacheEvict(value = {"category"} ,key = "'getLevel1Categorys'"),
@CacheEvict(value = {"category"} ,key = "'getCatalogJson'")
})
@Transactional
@Override
public void updateCascade(CategoryEntity category) {
this.updateById(category);
categoryBrandRelationService.updateCategory(category.getCatId(),category.getName());
}
@CacheEvict(value = {"category"},allEntries = true)
@Transactional
@Override
public void updateCascade(CategoryEntity category) {
this.updateById(category);
categoryBrandRelationService.updateCategory(category.getCatId(),category.getName());
}
【—>】@CachePut: 不影响方法执行更新缓存
对比@CacheEvict 返回值的数据需要替换redis缓存内容 不需要在下次读数据发现没有再填入数据。它的要求是数据要有返回值。
|