接下来使用Spring提供的缓存技术来实现Redis缓存的使用,在使用之前,需要了解缓存的两种模式:读模式和写模式,
读模式就是如何去读取一个数据,需要遵循现从缓存中读取,如果缓存中没有在去数据库中查询,查到数据就放到缓存中方便下一次使用;
写模式就是往缓存中存数据,但是写模式需要保持缓存和数据库数据的一致性,可以使用双写模式或失效模式
双写模式就是当我们修改了数据库中的某个数据时,将修改后的数据更新到缓存中,将旧的数据覆盖掉
失效模式同样的当修改了一个数据,我们就直接将当前数据所在的缓存之前全部清除掉,下一次查询时直接去数据库查询最新的数据
当然,在之前的使用,这些代码都是重复的,所以Spring专门抽取了一个针对的缓存的抽象层:Spring Cache;Spring从3.1开始定义了org. springframework.cache.Cache和org. springframework.cache.CacheManager接口来统一不同的缓存技术,并且支持JCache注解简化开发,相关操作可以参考官方文档(传送门)
接下来就开始使用Sring Cache
1. 导入jar包,注意需要使用哪种作为缓存就导入它,例如我用redis为例
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 编写配置,因为我使用的是Redis缓存,需要先配置Redis相关的
spring:
redis:
host: 192.168.0.109
cache:
type: redis # 指定缓存的类型
redis:
time-to-live: 3600000 # 过期时间,单位毫秒
key-prefix: cache_ # key的前缀
use-key-prefix: true # 是否使用前缀
cache-null-values: true # 是否缓存空值,防止缓存穿透
3. 先了解哈Cache的注解
- @Cacheable:触发将数据保存到缓存的操作
- @CacheEvict:触发将数据从缓存中删除的操作
- @CachePut:在不影响方法的执行的情况下更新缓存
- @Caching:组合多个缓存的操作
- @CacheConfig:在类级别共享缓存的相同配置
4. 自定义缓存配置类,并通过 @EnableCaching 注解开启缓存
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
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.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@EnableCaching // 开启缓存
@Configuration
@EnableConfigurationProperties(CacheProperties.class)//绑定属性配置
public class MyCacheConfig {
@Bean
public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
CacheProperties.Redis redisProperties = cacheProperties.getRedis();
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
//key的序列化方式
config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
//value的序列化方式
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()));
//过期时间
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
//key前缀
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
}
//是否缓存空值
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
//是否使用前缀
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
}
5. 开启测试,在测试中,第一次缓存中没有数据,执行了查询数据库,第二次缓存中有数据,直接返回了缓存中的数据而没有执行查询数据库
@Override
@Cacheable(value = RedisKeyUtils.catalogKey)//指定key
public List<CategoryEntity> getCatalogJsonWithRedisson() {
List<CategoryEntity> categoryEntities = listWithTree();
return categoryEntities;
}