一.Spring Cache
1.概述
Spring框架支持透明地向應(yīng)用程序添加緩存.抽象的核心是將緩存應(yīng)用于方法,從而根據(jù)緩存中可用的信息減少數(shù)據(jù)庫訪問的次數(shù).
緩存邏輯是透明地應(yīng)用的,不會對調(diào)用程序造成任何干擾.
只要通過@EnableCaching注釋啟用緩存支持,Spring Boot就會自動配置緩存基礎(chǔ)設(shè)施.
2.支持的緩存
緩存抽象不提供實(shí)際的存儲小腊,而是依賴于org.springframework.cache 和 org.springframework.cache.CacheManager 接口
- Generic
- JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, and others)
- EhCache 2.x
- Hazelcast
- Infinispan
- Couchbase
- Redis
- Caffeine
- Simple
二.幾個重要概念:
序號 | 名詞 | 說明 |
---|---|---|
01 | Cache | 緩存接口,定義緩存操作朴皆。實(shí)現(xiàn)有:RedisCache娩怎、EhCacheCache搔课、ConcurrentMapCache等 |
02 | CacheManager | 緩存管理器,管理各種緩存(cache)組件 |
03 | keyGenerator | 緩存數(shù)據(jù)時key生成策略 |
04 | serialize | 緩存數(shù)據(jù)時value序列化策略 |
三.幾個重要注解:
序號 | 注解 | 說明 |
---|---|---|
01 | @EnableCaching | 開啟基于注解的緩存 |
02 | @Cacheable | 主要針對方法配置截亦,能夠根據(jù)方法的請求參數(shù)對其進(jìn)行緩存 |
03 | @CachePut | 保證方法被調(diào)用爬泥,又希望結(jié)果被緩存。與@Cacheable區(qū)別在于是否每次都調(diào)用方法崩瓤,常用于更新. |
04 | @CacheEvict | 清空緩存 |
05 | @CacheConfig | 統(tǒng)一配置本類的緩存注解的屬性 |
06 | @Caching | 混合注解 |
四.幾個重要參數(shù):
@Cacheable/@CachePut/@CacheEvict 主要的參數(shù)
序號 | 參數(shù) | 說明 |
---|---|---|
01 | value | cacheNames的別名.即緩存的名稱 |
02 | cacheNames | 同value |
03 | key | 緩存的key,支持SPEL表達(dá)式.默認(rèn)為"" |
04 | keyGenerator | key生成器,默認(rèn)使用SimpleKeyGenerator,即根據(jù)Key數(shù)組生成一個字符串 |
05 | cacheManager | cache管理器 |
06 | cacheResolver | 自定義CacheResolver的bean名稱 |
07 | condition | 滿足某個條件時執(zhí)行,支持SPEL表達(dá)式 |
08 | unless | 滿足某個條件時不執(zhí)行,支持SPEL表達(dá)式.否定緩存, 當(dāng)條件為 true 時, 就不會緩存. |
09 | sync | 是否異步執(zhí)行 |
10 | allEntries | @CacheEvict獨(dú)有,是否清空所有的緩存 |
11 | beforeInvocation | @CacheEvict獨(dú)有,是否在方法執(zhí)行前就清空袍啡,缺省為 false,如果指定為 true却桶,則在方法還沒有執(zhí)行的時候就清空緩存境输,缺省情況下,如果方法執(zhí)行拋出異常,則不會清空緩存 |
五.緩存SpEL可用元數(shù)據(jù)
序號 | 名稱 | 位置 | 說明 | 舉例 |
---|---|---|---|---|
01 | methodName | Root object | 當(dāng)前被調(diào)用的方法名 | #root.methodName |
02 | method | Root object | 當(dāng)前被調(diào)用的方法 | #root.method.name |
03 | target | Root object | 當(dāng)前被調(diào)用的目標(biāo)對象 | #root.target |
04 | targetClass | Root object | 當(dāng)前被調(diào)用的目標(biāo)對象類 | #root.targetClass |
05 | args | Root object | 當(dāng)前被調(diào)用的方法的參數(shù)列表 | #root.args[0] |
06 | caches | Root object | 當(dāng)前方法調(diào)用使用的緩存列表(如@Cacheable(value={“cache1”, “cache2”}))嗅剖,則有兩個cache | #root.caches[0].name |
07 | Argument name | Evaluation context | 當(dāng)前被調(diào)用的方法的參數(shù)蛋逾,如findById(Long id),我們可以通過#id拿到參數(shù) | #iban or #a0 (you can also use #p0 or #p<#arg> notation as an alias). |
08 | result | Evaluation context | 方法執(zhí)行后的返回值(僅當(dāng)方法執(zhí)行之后的判斷有效,如‘unless','cache evict'的beforeInvocation=false) | #result |
六.SpringBoot使用
1.加入依賴
使用之前需要加入以下依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2.開啟自動配置
開啟緩存
@EnableCaching
@SpringBootApplication
public class SpringBootCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootCacheApplication.class, args);
}
}
3.使用 @Cacheable
使用 @Cacheable 注解后, 調(diào)用 findByName 會先從緩存中查找是否有對應(yīng)的數(shù)據(jù), 如果沒有才會去數(shù)據(jù)庫查找, 并將查找的結(jié)果放入緩存中.如果在緩存中查詢到數(shù)據(jù)則不會訪問方法體重的代碼.
1.方法運(yùn)行事前, 先去查詢 Cache(緩存組件),按照 cacheNames 指定的名字獲取:
(CacheManager 先獲取相應(yīng)的緩存),第一次獲取緩存如果沒有 Cache 組件會自動創(chuàng)建.
2.去 cache 中查找緩存的內(nèi)容,使用一個 key ,默認(rèn)就是方法的參數(shù):
key 是按照某種策略生成的,默認(rèn)使用的 keyGenerator生成的,默認(rèn)使用 SimpleKeyGenerator 生成 key
SimpleKeyGenerator 生成 key 的默認(rèn)策略:
如果沒有參數(shù), key = new SimpleKey()
如果只有一個參數(shù), key = 參數(shù)的值
如果有多個參數(shù), key = new SimpleKey(params)
3.沒有查詢到緩存就調(diào)用目標(biāo)方法:
4.將目標(biāo)方法返回的結(jié)果放進(jìn)緩存中.
@Cacheable
public ReturnDO<UserDetailDO> findByName(String name) {
log.info("UserDetailService|findByName|{}", name);
UserDetailDO userDetailDO = repository.findUserCacheDOByNameIs(name);
return ReturnDO.<UserDetailDO>builder().data(userDetailDO).build();
}
4.使用 @CachePut
被標(biāo)注@CachePut的方法,每次方法被調(diào)用均會執(zhí)行目標(biāo)方法,并對請求參數(shù)對其結(jié)果進(jìn)行緩存,這個注解主要用于新增數(shù)據(jù)和更新數(shù)據(jù)上(POST & PUT).
這里的KEY & VALUE必須和 @Cacheable KEY & VALUE 相同.
運(yùn)行時機(jī):
1.先調(diào)用目標(biāo)方法;
2.將目標(biāo)方法的結(jié)果緩存起來;
@CachePut(key = "#result.data.name")
public ReturnDO<UserDetailDO> update(UserDetailDO userCacheDTO) {
UserDetailDO userDetailDO = repository.save(userCacheDTO);
return ReturnDO.<UserDetailDO>builder().data(userDetailDO).build();
}
5.使用 @CacheEvict
@CacheEvict 的作用是根據(jù)一定的條件對緩存進(jìn)行清空(DELETE),該方法也是每次調(diào)用均會執(zhí)行,刪除數(shù)據(jù)同時刪除緩存中的數(shù)據(jù)
key:指定要清除的數(shù)據(jù)
allEntries = true:指定清除這個緩存中所有的數(shù)據(jù)
beforeInvocation = true: 緩存的清除是否在方法之前執(zhí)行
默認(rèn)代表緩存清除操作是在方法執(zhí)行之后執(zhí)行:如果出現(xiàn)異常緩存就不會清除
beforeInvocation = false: 緩存的清除是否在方法之后執(zhí)行
無論方法是否出現(xiàn)異常,緩存都清除
@CacheEvict
public ResponseEntity<Void> delete(String name) {
repository.deleteUserCacheDOByNameIs(name);
return new ResponseEntity<>(HttpStatus.OK);
}
6.使用 @CacheConfig
方法統(tǒng)一注解,一般注解到類上,表示該類方法中相同的注解配置使用值(統(tǒng)一設(shè)置配置).
@Slf4j
@Service
@CacheConfig(cacheNames = "redis_cache")
public class UserDetailService {
7.使用 @Caching
@Caching 復(fù)雜緩存配置
@Caching(
cacheable = {
@Cacheable(key = "#a0.name")
},
put = {
@CachePut(key = "#result.data.name"),
@CachePut(key = "#result.data.phone")
}
)
public ReturnDO<UserDetailDO> create(UserDetailDO userCacheDTO) {
UserDetailDO userDetailDO = repository.save(userCacheDTO);
return ReturnDO.<UserDetailDO>builder().data(userDetailDO).build();
}