以空间来换时间
什么是缓存
缓存是我们很常见的数据存储方式,不过相比较于直接存储,缓存牺牲了时效性与数据寿命,换来了更快的效率。
比如我们在使用一些常量数据时,如果每次都从数据源去查询,势必会浪费资源。因为这些数据的结果都是一致的,没有必要使用沉重的直接存储,可以换一种轻量的查询方式,比如放在内存中。
缓存模式
缓存可以像实际数据源一样使用存储逻辑,比如你对着数据库说这就是缓存,那它就是缓存,只是这个缓存方式效率低占用大。
一般情况下,我们采用的缓存都会比使用的数据存储对象更轻量,效率更高占用更低。那既然缓存效率又高占用又低,那为什么不直接作为数据存储对象来用呢?
缓存的劣势
缓存之所以效率高,是因为大部分的缓存都使用了键值对方式的非关系性存取模式,这使得缓存的存储结构相对简单,查询效率就会更高。但是这种方式是没办法满足大多数的业务需求的,比如对数据的多维搜索。
另外就是实时性,一般来说,我们对于缓存并不要求能实时更新,这就降低了缓存的存储消耗。比如对于搜索框下的热点列表,一般都是定时更新,这表示在缓存更新间隔内,哪怕热点真的改变了,但是你看到的热点列表也并不会更新。
还有一种更常用的缓存——内存缓存,不做文件存取能得到更高的查询效率,但是这也表示当内存断电后数据会消失,这就需要每次启动时重建缓存数据。我们经常使用的Map结构就是一个临时缓存。
缓存使用
基于缓存的特性,我们可以在不经常更新或是允许延迟更新数据的查询处使用缓存,比如之前提到的搜索热点
,比如省市区划树
。
另外,除了在数据库层级的缓存之外,在代码里也可以用到缓存。
预处理缓存
举个例子,我们总是会用到一些字符串处理方法。而某些时候,我们处理的字符串都是固定的,这时我们就可以用预处理缓存的方式。比较典型的例子就是正则工具。
1 | Pattern pattern = Pattern.compile("\\."); |
这里我们可以看出,Pattern
是个中间对象,但正是因为这个对象,我们就可以用一个正则去匹配各种需要处理的字符串。所以一般我们并不会设计这样的方法PatternUtil.matcher(String regex, String target)
,这个方法在我们重复处理同一个正则时会非常浪费性能。
所以Pattern
也是一个预处理缓存,相似的还有java.sql
包下的PreparedStatement
,这也是预处理的对象,可以重复利用来提高效率。
总结
缓存的目的是为了提高效率和降低数据存取负载,基于此我们才会去使用缓存,而不是盲目使用缓存。缓存最终的结果是以空间来换时间,这点就需要对不同的需求来作权衡了。
另外就是在作实际代码编写时,对于一些工具的写法也可以通过预处理缓存的模式来提升执行效率。