## 1 什麼是緩存 第一個問題,首先要搞明白什麼是緩存,緩存的意義是什麼。 對於普通業務,如果要查詢一個數據,一般直接select資料庫進行查找。但是在高流量的情況下,直接查找資料庫就會成為性能的瓶頸。因為資料庫查找的流程是先要從磁碟拿到數據,再刷新到記憶體,再返回數據。磁碟相比於記憶體來說,速度是很 ...
1 什麼是緩存
第一個問題,首先要搞明白什麼是緩存,緩存的意義是什麼。
對於普通業務,如果要查詢一個數據,一般直接select資料庫進行查找。但是在高流量的情況下,直接查找資料庫就會成為性能的瓶頸。因為資料庫查找的流程是先要從磁碟拿到數據,再刷新到記憶體,再返回數據。磁碟相比於記憶體來說,速度是很慢的,為了提升性能,就出現了基於記憶體的緩存。
這種基於記憶體的緩存,由於無法跟磁碟頻繁進行存儲,所以無法保證數據的完整性,隨時有可能丟失,所以架構一般使用資料庫加緩存的方式,資料庫用來持久化數據,緩存用來處理大流量。
2 本地緩存和集中式緩存
緩存按照存儲方式可以分為這本地緩存和集中式緩存。
本地緩存顧名思義就是存儲在本地上,例如靜態變數就可以說是一種本地緩存,存儲在了JVM中,或者說自己本地搭建的項目用的redis也算是本地緩存,因為緩存和應用都在一臺機器上。
本地緩存效率很高,直接讀取記憶體,沒有網路延遲,但是可用性很低,因為出現單點故障的話,資料庫和系統都會宕機。
對於大型項目來說,都會有集中式緩存,例如redis集群。緩存和應用伺服器是分離的,伺服器需要通過網路請求從緩存獲取數據,一般應用伺服器也會採取集群的方式,這樣可以保證高可用,數據不易丟失,而且也能保證各個伺服器的緩存數據一致。
對於分散式應用來說,本地緩存還會出現緩存不一致的問題,因為每個伺服器的本地緩存都是獨立的。
3 本地緩存的優點
剛纔說了這麼多本地緩存的缺點,那為什麼還要用呢?
因為如果都放在集中式緩存中,網路延遲會成為性能的瓶頸。因為不在本地記憶體,讀取的時間需要加上網路通信的時間。所以在對性能要求更大或者緩存內容不需要持久化、不需要一致性的情況下,本地緩存更適合。
所以一般的大型項目都採用本地緩存和集中式緩存混合使用的方式。
4 Spring對於緩存的支持
終於說到正題,本地緩存可以通過spring更簡單的管理和使用。
springboot和springmvc都支持緩存,其中CacheManager是Spring提供的緩存介面。
4.1 spring支持的CacheManager
看著非常多,實際上正常用的只有ConcurrentMapCacheManager
,EhCacheCacheManager
,GuavaCacheManager
(一般使用redis,我們需要更靈活的對redis鍵值進行操作,所以不用RedisCacheManager
),我們重點去講一下這個GuavaCacheManager
。
4.2 GuavaCache
Guava是谷歌開源的Java庫,其中的代表就有這個緩存。
GuavaCache的原理大概是LRU+ConcurrentHashMap
,載入在JVM的本地緩存
4.3 引入依賴
Spring Boot 基礎就不介紹了,推薦看這個實戰項目:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
//有可能需要這個
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
4.4 創建配置類
@EnableCaching
@Configuration
public class GuavaCacheConfig {
@Bean
public CacheManager cacheManager() {
GuavaCacheManager cacheManager = new GuavaCacheManager();
cacheManager.setCacheBuilder(
CacheBuilder.newBuilder().
expireAfterWrite(3, TimeUnit.MINUTES));
return cacheManager;
}
}
@EnableCaching用來開啟註解功能,這裡設置的失效時間是3分鐘。
Guava Cache 除了代碼中提到的設置緩存過期時間的策略外,還有其他的策略。下麵是 Guava Cache 設置緩存過期時間的策略:
- expireAfterAccess: 當緩存項在指定的時間段內沒有被讀或寫就會被回收。
- expireAfterWrite:當緩存項在指定的時間段內沒有更新就會被回收,如果我們認為緩存數據在一段時間後數據不再可用,那麼可以使用該種策略。
- refreshAfterWrite:當緩存項上一次更新操作之後的多久會被刷新。
4.5 緩存註解
標題終於出現了
我這裡就主要解釋下@Cacheable的用法,因為這個比較常見(其他的我也沒用過)
4.6 @Cacheable的用法
常用參數有
#
代表的是EL表達式
這裡的key和value和我們以為的緩存鍵值對是不一樣的
value+key 只是我們緩存鍵的名字,真正的值是方法的返回值。
舉一個例子
@Cacheable(value = "olympic_match_new_action",key = "'get_relate_news_'+#rsc")
public List<MatchNewsVO> getRelateNews(String rsc){
....
}
一般value取service名,key取方法名,取名按照資料庫的下劃線方式。後面那個#rsc指的是傳進來的參數,這些都是鍵。返回的List就是緩存的值。
5 @Cacheable失效的原因
在配置正常的情況下,本人親歷的失效原因就是一個類的方法調用了帶有緩存的方法,結果緩存失效。
我使用service的A方法,想調用這個service的緩存B方法,這樣是不行的。
原因是@Cacheable是由AOP代理實現,生成了帶有緩存的代理類。其他類想調用這個類的緩存方法時,會去調用這個代理類的方法,實現緩存功能。但是類內部調用這個方法,就不會去調用代理類的方法,導致緩存失效
6 總結
網上關於spring本地緩存的文章很少很雜,我稍微總結了一下發了出來,有自己的理解也有網上的摘抄。難免會有錯誤,希望大家指正
來源:blog.csdn.net/qq_37284798/article/details/129175161
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!
覺得不錯,別忘了隨手點贊+轉發哦!