Spring可以根据@Cacheable 、@CachePut 、@CacheEvict 、@EnableCaching等注解就可以实现对数据的缓存功能。
由于SpringBoot 2.x中默认并没有使用Redis连接池,所以需要在pom.xml中添加commons-pool2的依赖;
org.apache.commons
commons-pool2
org.springframework.boot
spring-boot-starter-data-redis
spring:
redis:
# Redis服务器地址
host: 192.168.1.111
# Redis数据库索引(默认为0)
database: 0
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
# 连接超时时间
timeout: 1000ms
lettuce:
pool:
# 连接池最大连接数
max-active: 8
# 连接池最大空闲连接数
max-idle: 8
# 连接池最小空闲连接数
min-idle: 0
# 连接池最大阻塞等待时间,负值表示没有限制
max-wait: -1ms
// 开启redis缓存功能
@EnableCaching
// 备注这是一个配置类
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* 配置redis模板文件
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisSerializer serializer = redisSerializer();
// 创建RedisTemplate对象
RedisTemplate redisTemplate = new RedisTemplate<>();
// 配置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
// redis key 序列化方式使用stringSerial
redisTemplate.setKeySerializer(new StringRedisSerializer());
// redis value 序列化方式使用jackson
redisTemplate.setValueSerializer(serializer);
// redis hash key 序列化方式使用stringSerial
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// redis hash value 序列化方式使用jackson
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 配置序列化
* @return
*/
@Bean
public RedisSerializer redisSerializer() {
// 定义Jackson2JsonRedisSerializer序列化对象
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会报异常
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);
return serializer;
}
/**
* 自定义缓存管理器
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
RedisCacheConfiguration redisCacheCOnfiguration= RedisCacheConfiguration
.defaultCacheConfig()
// 设置value 为自动转json的Object
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer()))
// 缓存有效期为一天
.entryTtl(Duration.ofDays(1));
return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
}
}
开启缓存功能,一般放在启动类上,也可放在redisConfig配置文件上。
使用该注解的方法当缓存存在时,会从缓存中获取数据而不执行方法,当缓存不存在时,会执行方法并把返回结果存入缓存中。
一般使用在查询方法上,可以设置如下属性:
value:缓存名称(必填),指定缓存的命名空间;
key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义,如果不指定,则缺省按照方法的所有参数进行组合;
unless:条件符合则不缓存;
condition:条件符合则缓存。
执行这个方法的时候,会先去redis中,根据ceshi::user:id(这个id就是前段传来的id)作为key去查找,如果找到直接返回redis中的数据
如果没有找到就执行该方法,由于unless属性,当返回结果为空就不存入redis中,这里的result是固定写法,指的就是当前返回值User
当不指定key的时候,就会以方法名作为key,这里就是以id作为key。
@Cacheable(value = "ceshi", key = "'user:'+#id", unless = "#result==null")
@GetMapping("{id}")
public User getUserById(@PathVariable("id") Long id) {
User user = new User();
user.setAge(1);
user.setUserId(10L);
user.setUsername("张三");
user.setPassword("123");
user.setToken("2223334455:333:332");
return user;
}
ceshi::user:id在工具中会以:分隔,所以就会出现图片中的ceshi下一级为空的样子。
使用该注解的方法每次执行时都会把返回结果存入缓存中。
一般使用在新增方法上,但是本人觉得新增可以不增加缓存,当查询到这个数据的时候没有再添加缓存即可,可以设置如下属性:
value:缓存名称(必填),指定缓存的命名空间;
key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义,如果不指定,则缺省按照方法的所有参数进行组合;
unless:条件符合则不缓存;
condition:条件符合则缓存。
// 更新ceshi 缓存
@CachePut (value= "ceshi" ,key= "#account.getName()" )
public Account updateAccount(Account account) {
return updateDB(account);
}
使用该注解的方法执行时能够根据一定的条件对缓存进行清空。
一般使用在更新或删除方法上,可以设置如下属性:
value:缓存名称(必填),指定缓存的命名空间;
key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义;
condition:条件符合则缓存。
allEntries:是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存
beforeInvocation:是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存
// 清空key为ceshi::user:id 的缓存
@CacheEvict(cacheNames = "ceshi", key = "'user:'+#id")
@DeleteMapping("{id}")
public int deleteObject(@PathVariable("id") Long id) {
return 0;
}
// 清空ceshi 所有缓存
@CacheEvict (value= "ceshi" ,allEntries= true )
public void reload() {
reloadAll()
}
// 清空ceshi下 userName.length() <=4的缓存
@Cacheable (value= "ceshi" ,cOndition= "#userName.length() <=4" )
public Account getAccountByName(String userName) {
// 方法内部实现不考虑缓存逻辑,直接实现业务
return getFromDB(userName);
}
但是以上的做缓存都是粒度比较大的,如果想单独做一些缓存,设置特定的时间什么的,就需要用到以下的工具类
/**
* spring redis 工具类
**/
@Component
public class RedisCache {
@Autowired
public RedisTemplate redisTemplate;
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public void setCacheObject(final String key, final T value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout) {
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit) {
return redisTemplate.expire(key, timeout, unit);
}
/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public T getCacheObject(final String key) {
ValueOperations operation = redisTemplate.opsForValue();
return operation.get(key);
}
/**
* 删除单个对象
*
* @param key
*/
public boolean deleteObject(final String key) {
return redisTemplate.delete(key);
}
/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/
public long deleteObject(final Collection collection) {
return redisTemplate.delete(collection);
}
/**
* 缓存List数据
*
* @param key 缓存的键值
* @param values 待缓存的List数据
* @return 缓存的对象
*/
public long setCacheList(final String key, final List dataList) {
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
return count == null ? 0 : count;
}
/**
* 获得缓存的list对象
*
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public List getCacheList(final String key) {
return redisTemplate.opsForList().range(key, 0, -1);
}
/**
* 缓存Set
*
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
public long setCacheSet(final String key, final Set dataSet) {
Long count = redisTemplate.opsForSet().add(key, dataSet);
return count == null ? 0 : count;
}
/**
* 获得缓存的set
*
* @param key
* @return
*/
public Set getCacheSet(final String key) {
return redisTemplate.opsForSet().members(key);
}
/**
* 缓存Map
*
* @param key
* @param dataMap
*/
public void setCacheMap(final String key, final Map dataMap) {
if (dataMap != null) {
redisTemplate.opsForHash().putAll(key, dataMap);
}
}
/**
* 获得缓存的Map
*
* @param key
* @return
*/
public Map getCacheMap(final String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 往Hash中存入数据
*
* @param key Redis键
* @param hKey Hash键
* @param value 值
*/
public void setCacheMapValue(final String key, final String hKey, final T value) {
redisTemplate.opsForHash().put(key, hKey, value);
}
/**
* 获取Hash中的数据
*
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public T getCacheMapValue(final String key, final String hKey) {
HashOperations opsForHash = redisTemplate.opsForHash();
return opsForHash.get(key, hKey);
}
/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public List getMultiCacheMapValue(final String key, final Collection hKeys) {
return redisTemplate.opsForHash().multiGet(key, hKeys);
}
/**
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
*/
public Collection keys(final String pattern) {
return redisTemplate.keys(pattern);
}
}
参考:http://www.macrozheng.com/#/reference/spring_data_redis
http://www.ruoyi.vip/