重写Spring插件RedisCache实现以通配符方式删除缓冲数据

    上一篇讲了spring如何集成redis组件并成功用@Cache注解将getOrderList文件返回的数据缓冲. 这里再补充说明如何实现以通配符方式注解@CacheEvict删除缓冲数据.


    Spring-Redis-data提供的Redis集成缓冲组件在Redis服务器上生成的keyset以zset格式存在,如下图:

重写Spring插件RedisCache实现以通配符方式删除缓冲数据_第1张图片

但是Redis并没有提供以通配符匹配的功能检索zset里面存储的key value. @CacheEvict也只能指定具体的key value 删除 指定的缓冲数据,但这种单调的功能往往不能满足实际应用的需要 .

     以下一个应用场景, 比如将检索订单进行缓冲, 分页保存,又因为每一页的查询条件有变动,所以每一页一个缓冲数据(听上去redis得需要有足够内存才跑得爽^_^ ).  所以,当增加/删除/更新订单时, 则需要将key list中包含"订单检查缓冲"这些数据所有key全部删除以便查询时重新从数据库中实时取数.

    首先我们要编写MyRedisCache.java来扩展RedisCache, 以上图为例, pageCache~keys这组key set里面在实际应用中有可能高达几万至几十万的key,如果用zrange取回全部再查找,必然会有网络延时的损耗. 所以本文利用一个全局对象List 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() {
				@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 lvTmp=new ArrayList();
					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) {
	....


你可能感兴趣的:(Redis,Spring,大杂烩)