redis 缓存空值
redis缓存空值可以在一定程度上应对高并发的场景下的缓存穿透
*********************
相关类
RedisCacheConfiguration
public class RedisCacheConfiguration {
private final Duration ttl; //过期时间
private final boolean cacheNullValues; //缓存空值
private final CacheKeyPrefix keyPrefix; //缓存键的前缀
private final boolean usePrefix; //是否使用前缀
private final SerializationPair<String> keySerializationPair;
private final SerializationPair<Object> valueSerializationPair;
private final ConversionService conversionService;
***********
构造函数
private RedisCacheConfiguration(Duration ttl, Boolean cacheNullValues, Boolean usePrefix, CacheKeyPrefix keyPrefix, SerializationPair<String> keySerializationPair, SerializationPair<?> valueSerializationPair, ConversionService conversionService) {
this.ttl = ttl;
this.cacheNullValues = cacheNullValues;
this.usePrefix = usePrefix;
this.keyPrefix = keyPrefix;
this.keySerializationPair = keySerializationPair;
this.valueSerializationPair = valueSerializationPair;
this.conversionService = conversionService;
}
***********
静态方法:返回RedisCacheConfiguration对象实例,默认可缓存空值
public static RedisCacheConfiguration defaultCacheConfig() {
return defaultCacheConfig((ClassLoader)null);
}
public static RedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader classLoader) {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
registerDefaultConverters(conversionService);
return new RedisCacheConfiguration(Duration.ZERO, true, true, CacheKeyPrefix.simple(), SerializationPair.fromSerializer(RedisSerializer.string()), SerializationPair.fromSerializer(RedisSerializer.java(classLoader)), conversionService);
}//返回RedisCacheConfiguration对象实例,默认可缓存空值
***********
常用方法
public RedisCacheConfiguration entryTtl(Duration ttl) {
//设置缓存过期时间
public RedisCacheConfiguration prefixKeysWith(String prefix) {
//设置缓存前缀
public RedisCacheConfiguration disableCachingNullValues() { //禁用缓存空值
public RedisCacheConfiguration disableKeyPrefix() { //禁用缓存前缀
public RedisCacheConfiguration serializeKeysWith(SerializationPair<String> keySerializationPair) { //设置key序列化器
public RedisCacheConfiguration serializeValuesWith(SerializationPair<?> valueSerializationPair) { //设置value序列化器
public boolean usePrefix() { //是否使用缓存前缀
public boolean getAllowCacheNullValues() { //是否允许缓存空值
public SerializationPair<String> getKeySerializationPair() { //获取key序列化转换器
public SerializationPair<Object> getValueSerializationPair() { //获取value序列化转换器
public String getKeyPrefixFor(String cacheName) { //获取cacheName的缓存前缀
。。。。
}
*********************
使用示例
**************
config 层
RedisCacheConfig
@Configuration
@EnableCaching
public class RedisCacheConfig {
@Bean
public CacheManager initCacheManager(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration cacheConfiguration= RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()))
.entryTtl(Duration.ofMinutes(2L));
Map<String,RedisCacheConfiguration> map=new HashMap<>();
map.put("custom",cacheConfiguration);
return RedisCacheManager.builder(connectionFactory)
.withInitialCacheConfigurations(map)
.transactionAware()
.build();
}
}
**************
serviceImpl 层
PersonServiceImpl
@Service
public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person> implements PersonService {
@Resource
private PersonMapper personMapper;
@Override
@Cacheable(value = "custom",key="'person'+#id")
public Person getById(Integer id) {
System.out.println("查询id为:"+id+"的person");
return personMapper.selectById(id);
}
@Override
@CachePut(value = "custom",key = "'person'+#person.id")
public Person add(Person person) {
personMapper.insert(person);
return person;
}
@Override
@CacheEvict(value = "custom",key = "'person'+#id")
public void deleteById(Integer id) {
personMapper.deleteById(id);
}
}
**************
controller 层
PersonController
@RestController
@RequestMapping("/person")
public class PersonController {
@Resource
private PersonService personService;
@RequestMapping("/add")
public String add(){
for (int i=0;i<100;i++){
Person person=new Person();
person.setName("瓜田李下"+i);
person.setAge(10+i%10);
personService.add(person);
}
return "success";
}
@RequestMapping("/get")
public String get(@RequestParam("id") Integer id){
Person person= personService.getById(id);
if (person!=null){
System.out.println(person);
return person.toString();
}else {
System.out.println("查找的id为:"+id+" 的person不存在");
return "查找的id为:"+id+" 的person不存在";
}
}
@RequestMapping("/delete")
public String delete(Integer id){
personService.deleteById(id);
return "success";
}
}
*********************
使用测试
查询id为:2的person
Person(id=2, name=瓜田李下1, age=11)
Person(id=2, name=瓜田李下1, age=11)
查询id为:400的person
查找的id为:400 的person不存在
查找的id为:400 的person不存在
说明:后端数据库不存在id为400的person,首次查询到后端数据库查询,再次查询时由于缓存了空值,没到后端数据库查询