问题:
当数据库中存在大量数据,更新频率低,且查询速度较慢时,应该如何提高查询速度?
第一个想法是将无查询条件查出的所有数据,存放在redis中。每次查询时,根据查询条件对redis中取出的数据进行筛选过滤分页,再将结果返回。
但实际操作的时候发现,数据量过大,无论是保存对象集合或者是字符串,都会报内存溢出的错误 Out of Memory allocation。
一、Spring Cache
当调用一个方法时,会把该方法参数和返回结果作为一个键值对存放在缓存中。等下次使用同样的参数调用该方法时,不再执行该方法,而是直接从缓存中获取结果进行返回。需要保证对于一个相同的方法,相同的参数要有相同的返回结果。
提供注解:
@Cacheable:使用@Cacheable标记的方法在执行后Spring Cache将缓存其返回结果
@CacheEvict:会在方法执行前或者执行后移除Spring Cache中的某些元素
@Cacheable
@Cacheable(value=”findList”);
public List<String> findList(QueryParam param) {
return xxxxMapper.findList(param);
}
当调用这个方法时,会从名为findList的缓存中查询。如果没有,则执行方法,并将结果存入缓存中;否则返回缓存中的结果。上述例子中的,缓存的key为param中的参数以及值,value为List对象。
@Cacheable可配置参数:
value:缓存名称,必须指定至少一个。
key:缓存的key,可以为空(为空时根据redisConfig中的keyGenerator自定义生成)。指定要按照SpEL表达式进行编写。
condition:缓存条件,可以为空。指定要按照SpEL表达式进行编写。返回true/false,仅返回true时进行缓存。
eg:@Cacheable(value = "findList", key = "#param.name", condition = "#param.name != null" )
KeyGenerator
spring默认的生成策略DefaultKeyGenerator:
- 参数为空:返回0
- 有一个参数且为null:返回53
- 参数不是数组:返回参数
- 其他情况:返回hashCode
当参数列表的值相同时,返回的值是一样的,会导致获取到错误的缓存数据。
自定义cache key的生成方式:
类名 + 方法名 + 参数列表 + 参数值 ——> 哈希散列
@EnableCaching
@Slf4j
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* 自定义key生成规则
* @return
*/
@Override
public KeyGenerator keyGenerator(){
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append("&");
sb.append(method.getName());
sb.append("&");
for (Object obj : params) {
if (obj != null){
sb.append(JSON.toJSONString(obj));
}
}
log.info("redis cache key str: " + sb.toString());
log.info("redis cache key sha256Hex: " + DigestUtils.sha1DigestAsHex(sb.toString()));
return DigestUtils.sha1DigestAsHex(sb.toString());
}
};
}
}
参数示例:
public class QueryParam {
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("页码")
private Integer pageNum;
@ApiModelProperty("页面大小")
private Integer pageSize;
}
key示例:
包名.类名&findList&{"name":"","pageNum":1,"pageSize":10}
二、使用步骤
1.在redisConfig中配置@EnableCaching注解,继承CachingConfigurerSupport类,并实现自定义key生成方法。如上文。
2.在对应的方法上标注@Cacheable(value = “方法名”)
参考文章:
Spring缓存注解@Cache使用
spring boot cache redis 简单理解自定义 KeyGenerator