上一篇讲了spring如何集成redis组件并成功用@Cache注解将getOrderList文件返回的数据缓冲. 这里再补充说明如何实现以通配符方式注解@CacheEvict删除缓冲数据.
但是Redis并没有提供以通配符匹配的功能检索zset里面存储的key value. @CacheEvict也只能指定具体的key value 删除 指定的缓冲数据,但这种单调的功能往往不能满足实际应用的需要 .
以下一个应用场景, 比如将检索订单进行缓冲, 分页保存,又因为每一页的查询条件有变动,所以每一页一个缓冲数据(听上去redis得需要有足够内存才跑得爽^_^ ). 所以,当增加/删除/更新订单时, 则需要将key list中包含"订单检查缓冲"这些数据所有key全部删除以便查询时重新从数据库中实时取数.
首先我们要编写MyRedisCache.java来扩展RedisCache, 以上图为例, pageCache~keys这组key set里面在实际应用中有可能高达几万至几十万的key,如果用zrange取回全部再查找,必然会有网络延时的损耗. 所以本文利用一个全局对象List<Object> mKeyElements来保存一份key 重列表在内存中又加快数据存储速度, 这份扩展也重写了evict(Object)这个方法,使其能使用正则表达式来匹配.需要注意的是,mKeyElements必须定义为线程安全的List,因为这个实例是单实例,全webapp通用的.
@Override
public void clear() {
super.clear();
mKeyElements.clear();
}
@Override
public void put(final Object key, final Object value) {
super.put(key, value);
mKeyElements.add(key);
}
private void evictx(Object key) {
super.evict(key);
}
@SuppressWarnings("unchecked")
@Override
public void evict(Object key) {
if (key != null && key instanceof String && ((String) key).startsWith("regex:")) {
//final String lvsRedisKey = this.getName() + "~keys";
mRedisOperations.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
String lvsPattern = ((String)key).split("regex:")[1];
lvsPattern=lvsPattern.replace("*", ".*").replace("?", "\\w");
Pattern lvPattern=Pattern.compile(lvsPattern);
List<Object> lvTmp=new ArrayList<Object>();
for (Object item:mKeyElements) {
if (lvPattern.matcher((String)item).matches()) {
lvTmp.add(item);
evictx(item);
}
}
mKeyElements.removeAll(lvTmp);
return true;
}
});
} else {
super.evict(key);
mKeyElements.remove(key);
}
// System.out.println(key);
}
上面代码,在循环外面先定义Pattern,在循环里面用matcher来匹配, 要比在循环里面直接用静态方法Pattern.matches要快33%左右, 对于超大数据应用环境, 这种细节的优化不可忽视.
调用:
...
@CacheEvict(value= "pageCache",key="'regex:*QuotedNoteModule*OrderList*'")
public String updateQuotedNoteList(CommonReqUpdBean pvReq,String pvLogin, Locale pvLocale) {
//Locale lvLocale=getLocale(pvRequest);
JSONData lvRet = new JSONData();
lvRet.result=null;
try {
for (CommonReqUpdBean.DataBean bean : pvReq.data) {
....