通常在使用Redis 直接做业务缓存时,判断逻辑流程如下:
代码逻辑如下:
public List<String> getRedisCacheResult(){
//查询缓存结果集
Object test = redisTemplate.opsForValue().get("test");
//缓存为空
if(ObjectUtils.isEmpty(test)){
//和DB 交互,获取业务数据
List<String> list = new ArrayList<>();
list.add("test");
//将DB 查询的结果集放入缓存
redisTemplate.opsForValue().set("test",list);
return list;
}
//缓存存在结果集,返回缓存中的结果集
return (List<String>)test;
}
整个代码逻辑流程会发现,每次进行数据缓存的时候,都会存在代码冗余逻辑判断。该逻辑判断如果采用Spring Cache + Redis 注解的方式,代码更加简洁方便
<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>
@EnableCaching 注解用来开启缓存,并配置Redis缓存管理器。如果未配置该注解,则配置的cache +redis无法生效
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory){
//设置key 默认过期时间未30min
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30L)).disableCachingNullValues();
return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory))
.cacheDefaults(redisCacheConfiguration).transactionAware().build();
}
}
package com.corn.redis.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* author:zj
* Date:2020/4/5
* Time:15:18
*/
@Service
@CacheConfig(cacheNames = "RedisCacheService")
@Slf4j
public class RedisCacheService {
/**
* 将结果集缓存,当结果集已缓存,从缓存中获取结果集,一般长用于数据删除
* @return
*/
@Cacheable(value = "cacheTest",key = "#root.methodName")
public List<String> getRedisCache(){
List<String> list = new ArrayList<>();
list.add("test");
return list;
}
/**
* 将结果集缓存,和@Cacheable 的区别是,该缓存不管缓存是否存在,每次都会更新缓存
* 常用于更新结果集
* @return
*/
@CachePut(value = "cacheTest",key = "#root.methodName")
public List<String> updateRedisCache(){
List<String> list = new ArrayList<>();
list.add("test");
return list;
}
/**
* 根据key 删除指定存储空间下的缓存
*
*/
@CacheEvict(value = "cacheTest",key = "#root.methodName")
public void deleteRedisCache(){
log.info("清理指定key下缓存");
}
/**
* 清空当前缓存空间下的所有缓存
*/
@CacheEvict(allEntries = true)
public void deleteAllCache(){
log.info("清除当前缓存空间下的所有缓存");
}
}
注解 | 作用 | 使用场景 |
---|---|---|
@CacheConfig | 类级别注解,常用于设置类缓存共通的配置,比如@CacheConfig(cacheNames = “RedisCacheService”) 设置该类下缓存的缓存空间为RedisCacheService | 常用于统一整个类下的缓存空间及key生成策略 |
@Cacheable | 将方法的查询结果缓存起来,如果缓存中有值,则不在执行该方法 | 常用于查询数据业务逻辑 |
@CachePut | 将结果集缓存,和@Cacheable 的区别是,该缓存不管缓存是否存在,每次都会更新缓存常用于更新结果集 | 常用于数据结果集更新时使用 |
@CacheEvict | 根据键值进行删除缓存 | 常用于数据清除数据时同时 将缓存进行清除 |
Example | Description |
---|---|
#root.methodName | 被调用的方法名称作为key |
#root.method.name | 被调用的方法作为key |
#root.target | 被调用的方法对象作为key |
#root.targetClass | 当前方法所在类作为key |
#root.args[0] | 当前方法中的参数作为key |
key 自定义方式使用:
@Cacheable(cacheNames="user", key="#isbn")
public User findUser(User isbn, boolean checkWarehouse, boolean includeUsed)
@Cacheable(cacheNames="user", key="#isbn.rawNumber")
public User findUser(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
@Cacheable(cacheNames="user", key="T(someType).hash(#isbn)")
public User findUser(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
@Cacheable(cacheNames="user", sync=true)
public User test(String id) {...}
//当name 的长度小于16 时进行数据的缓存,否则不进行缓存
@Cacheable(cacheNames="user", condition="#name.length() < 16")
public User findUser(String name)
//当name 长度小于32 且 查询到的用户年龄大于12 岁时才进行结果集的缓存
@Cacheable(cacheNames="user", condition="#name.length() < 32", unless="#result.age<12")
public User findUser(String name)
Spring cache + redis 进行缓存管理的方式,在一定程度上,减少了代码。实际使用过程中还是需要结合业务场景,决定是单独使用Redis 还是使用Redis + Spring Cache 组合方式
参考:
https://www.jianshu.com/p/931484bb3fdc