缓存简介
什么是缓存
缓存是存储在内存中的数据,相比硬盘读写更快。
缓存能做什么
主要就是减轻数据库压力,加快响应速度。
-
预读取:在系统对外提供服务之前,提前将一部分热点数据从硬盘加载到内存,减少上线时服务器的压力。
-
延迟写:数据库写入为了保证准确性所以很慢。可以将写入请求先堆积在缓存,之后一次批量写入数据库,可以缓解对数据库频繁修改的压力。只能用于对数据精度要求不高的场景,存在数据丢失的可能。
什么时候使用缓存
**1)业务流量量级以及应用规模:**对于低并发低流量的应用而言,引入缓存并不会带来性能的显著提升,反而会带来应用的复杂度以及极高的运维成本。
- 热点数据:每秒几十次以上的访问
- 静态数据:很少变化,读远大于写,如几天一变化
在哪里使用缓存
浏览器缓存 --》 CDN缓存 --》 网关(代理)缓存 --》 进程内缓存 --》 进程外缓存 --》 数据库缓存
从网关开始就是程序员自己能控制的了。常用的代理缓存有Nginx,Varnish(大量小文件),Squid(全面但成本高)。
进程内缓存:EhCache。相比于进程外缓存省去网络开销,响应时延更低。但数据存储多份(多个服务节点内)难保持一致性。
进程外缓存有:Redis(数据库结构更多),Memcached(纯kv且数据量大时会快一些,但可能丢失数据,是纯内存的)
使用缓存的弊端
- 缓存更新
- 缓存和数据的一致性
- 缓存雪崩
- 缓存穿透
- 缓存并发
- …
Spring 缓存
项目缓存—> Spring cache —> Spring EL表达式 —>
基于注解:
@Cacheable
-
在方法被调用后,Spring会将返回值缓存起来,下次用同样的参数执行该方法时,直接从缓存取结果,不需要再执行方法。
-
可以标注在方法上,表示方法支持缓存;可以标注在类上,表示类中所有方法支持缓存。
-
Spring是以键值对的方式缓存方法返回值的。
-
有三个属性:value、key、condition
@CachePut
- 不同于@Cacheable可能会不执行方法,@CachePut每次都会执行方法,并且把返回值放入缓存中。
- 用法与@Cacheable一致。
@CacheEvict
- 用来清除缓存的注解。可以标注在方法上和类上。
- 有五个属性:value、key、condition、allEntries、beforeInvocation
- value、key、condition用法与@Cacheable相似。
- allEntries:表示是否需要清除缓存中的所有元素,为boolean类型。true的话将忽略指定的key,清除指定cache中的所有元素。
- beforeInvocation:清除操作默认是在方法执行成功后执行的,如果方法抛出异常未成功返回,则不会清除缓存。此属性为true时,使得清除操作在方法执行前清除缓存中的元素。
@Caching
- 使得可以在一个类或方法上同时指定多个Cache注解。
- 有三个属性:cacheable、put和evict,分别对应三个注解。
基于XML配置:
-
<cache:advice 下定义多个 <cache:caching
-
<cache:caching 下定义多个 <cache:cacheable 、<cache:cache-evict 、<cache:cache-put
<cache:advice id="cacheAdvice" cache-manager="cacheManager"> <cache:caching cache="users"> <cache:cacheable method="findById" key="#p0"/> <cache:cacheable method="find" key="#user.id"/> <cache:cache-evict method="deleteAll" all-entries="true"/> </cache:caching> </cache:advice>
-
使用 <aop:config> 将<cache:advice 织入spring中。
配置Spring对Cache的支持
- 声明对Cache的支持
- 基于注解:<cache:annotation-driven/>
- 基于xml:即上面的
- 配置CacheManager
- Spring提供了两种CacheManager的实现。一种是基于Java API的ConcurrentMap,另一种是基于Ehcache。
- 配置<bean>即可,略。
键的生成策略
-
默认策略
默认的生成策略是通过KeyGenerator生成的,默认如下:
- 如果方法没有参数,则使用0作为key;
- 如果方法有一个参数,则使用该参数为key;
- 如果方法有多个参数,则使用所有参数的hashCode作为key。
也可以指定自己的KeyGenerator,配置略。
-
自定义策略
我们通过Spring EL表达式来指定key。
-
直接使用 “#参数名” 或者 “#p参数索引”。如 key="#id",key="#p0"
-
使用Spring提供的root对象。
属性名称 描述 示例 methodName 当前方法名 #root.methodName method 当前方法 #root.method.name target 当前被调用的对象 #root.target targetClass 当前被调用的对象的class #root.targetClass args 当前方法参数组成的数组 #root.args[0] caches 当前被调用的方法使用的Cache #root.caches[0].name
-
补充:
- 使用@Cacheable不缓存空值。
@Cacheable(value = "organCache", unless = "#result == null")