您的位置:首页 > 编程语言 > Java开发

关于Spring Cache的一些应用上的遗憾

2017-09-21 08:57 246 查看
前端时间看了《Spring 实战》这本书,其中有基于对缓存的支持,并且其中的CacheManager可以支持许多主流的缓存技术,例如redis,这个发现令我非常激动,因为我曾为了公司的业务需求编写了一套适用于本公司的缓存策略,具体可查看我的博文 spring
aop结合redis实现数据缓存,就像发现新大陆似得去研究springCache,但是结果让我不甚满意,纵观全书和网上不少资料,发现springCache的功能似乎有些鸡肋...即对许多多表连接查询的缓存如何做到实时的更新或者清除

@CachePut:

书上的解释是,标注了该注解的方法始终都会被调用,且方法的返回值也会放到缓存中,这提供了很便利的机制,能够让我们在请求之前预先加载缓存

通常应用在添加或者更新的接口上同时对缓存进行实时更新。

引用其他网友帖子上的例子就是:

@Cacheable(value="accountCache")// 例1:使用了一个缓存名叫 accountCache
public Account getAccountByName(String accountName) {
// 方法内部实现不考虑缓存逻辑,直接实现业务
return getFromDB(accountName);
}

// 例2:更新 accountCache 缓存
@CachePut(value="accountCache",key="#account.getName()")
public Account updateAccount(Account account) {
return updateDB(account);
}

例1对指定account进行了查询并且缓存,key为它的accountName,例2更新指定的account,并且对返回值进行缓存,key为它的accountName,做到了更新数据后即实时更新缓存的效果。

这是一个基础的例子,书上和网上的例子也大多类似,那么我的疑问来了,假如针对这条account数据,应用中有其他接口对其进行了多表连接的查询并进行了缓存,即缓存中存在这条account的部分数据比如accountName等....那么@CachePut如何做到实时更新这些类似的多表连接缓存??暂且不说能否获取到所有类似查询所缓存的key值,即使能获取到,@CachePut的key属性只允许接受字符串,换句话说只允许接受一个key,再换句话说就只能更新当前所做的更新或者添加操作对应的那个account的缓存!Excuse
Me?!? (其实实时更新所有对应的缓存本身对于缓存体系而言都是一个普遍性的挑战,甚至我认为即使可以做到,也完全没必要,想象一下一次性可能执行上百条查询来重新加载缓存,关键这种更新频率可能还挺高,即使采取异步的形式对系统而言压力依然很大,完全可以先清空相应缓存,等要去调用的时候自然会重新加载新的缓存。我寄希望于springCache可以帮我们做到这种实时更新,但是既然做不到,那么@CachePut可用性依然不高...)

@CacheEvict:

书上的解释是可以用该注解来移除缓存条目

见示例:

@CacheEvict(value="accountCache",key="#account.getName()")
public void removeAccount(Account account) {
removeDB(account);
}

@CachePut同样的问题,对于@cacheEvict 或许有一种方案可以解决,value结合allEntries属性,将所有类似的缓存放在同一个名称的缓存类目下面,最后进行无差别清除缓存,value可以接受字符串类型的数组,可以一次清空多个类目,这个方案勉强可以实现数据更新即清除相应缓存的目的,修改后的例子类似这样……

@CacheEvict(value={"accountCache","account&otherCache"},allEntries=true)
public void removeAccount(Account account) {
removeDB(account);
}


但是依然存在很大的不足,就像上面例子看到的一样,value属性不支持spel表达式!!!也就是说须要我们自己手动的去维护(添加,去除一个类目),当类目少还好说,超过十个我都不想去维护它,你得分清每个类目具体对应哪些缓存数据,最后维护到你怀疑人生……我们说,不管开发人员再细心,一个须要依靠开发人员自身去维护的策略都是不可信的,指不定你就漏掉哪个缓存了呢,我们须要的是一套成熟的代码层面的策略,例如通过spel表达式调用工具类的方法获取相应类目,不须要再去人工干预,一劳永逸,这一点,springCache并没有做到……

所以之所以说鸡肋,对于@CachePut注解,不能同时更新所有关联查询的缓存,可以用,但是你要确保这个表的数据现在,将来百分百不会被其他接口关联查询到,对于企业级应用来说基本上是不可能出现这种表,极个别有的,如果不能从数据库层面控制这张表的不可被关联性质,那么就有被关联的可能性,我们依然认为这是不可控,不可信的

而对于@CacheEvict注解,可用性同样不高,或许有好的解决方案我不知道的,但直到现在,我没有从书中得到我想要的答案,网上资料;官方文档也只是简单的demo,并没有深入,所以对于springCache仅限于理论研究,没有应用到现有系统中...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring cache redis