數據庫的數據是存儲在硬盤上的,頻繁訪問性能較低。而緩存數據存儲在內存中,訪問性能比硬盤快了一個數量級。如果將一些需要頻繁查詢的熱數據放到緩存中,可以大大減輕數據庫的訪問壓力。
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
啓用緩存
在配置類中添加以下註解
@EnableCaching
使用緩存
出於方便,這裏直接在控制層做緩存。 @GetMapping("/find")
@Cacheable(cacheNames = "hello")
public String find() {
System.out.println("從數據庫查詢數據,並用return返回");
return "該數據會被緩存";
}
- @Cacheable:指在執行find方法前,首先查找該方法是否有緩存,如果有則直接返回緩存,如果沒有則執行方法。
- cacheNames:指定緩存的名稱,不同緩存的數據是彼此隔離的。
緩存的key
上面cacheNames指定了緩存名稱,但是每個方法由於傳參不同,其return數據也會不同,所以一個方法中可能會有多個緩存。要在同一個cacheNames中區別不同的緩存,就需要使用key。修改前兩行代碼,給find方法傳入了一個User,這是我自定義的類,其中有一個id參數。同時指定了key爲"#user.id",這是SpEL表達示,指使用user的id作爲當前緩存的key。關於SpEL更多 語法可自行百度。
@GetMapping("/find")
@Cacheable(cacheNames = "hello",key = "#user.id")
public String find(User user) {
- 現在訪問http://localhost:8080/find?id=1,此時id參數會傳入user,最終該緩存的key爲1。
- 然後訪問http://localhost:8080/find?id=2,此緩存的key爲2,與上面的1不一樣,所以它們不是同一個緩存。
修改緩存
@GetMapping("/update")
@CachePut(cacheNames = "hello", key = "#id")
public String update(String id) {
System.out.println("讀取修改後的數據");
return "修改後的緩存數據";
}
- @CachePut:無論是否存在緩存,它都會執行,而且用return數據刷新緩存。
- cacheNames:指定要修改的key所屬的cacheNames。
- key:這裏方法參數就是id,所以可以直接用#id。
訪問http://localhost:8080/update?id=1,此時key爲1的緩存將被修改。之後再訪問http://localhost:8080/find?id=1,都會得到修改後的數據,find方法中原有的數據被替換了。
刪除緩存
訪問http://localhost:8080/delete?id=1,即可刪除key爲1的緩存,和上面一樣的原理。
@GetMapping("/delete")
@CacheEvict(cacheNames = "hello", key = "#id")
public String delete(String id) {
return "刪除成功";
}
condition條件
如果只想將id爲1的查詢寫入緩存,而其他數據不需要緩存。可以添加condition緩存條件,如下。這裏id參數是個字符串型,所以加了單引號,否則1就是整數,條件不成立。@Cacheable(cacheNames = "hello",key="#user.id",condition ="#user.id=='1'" )
此時,只有訪問http://localhost:8080/find?id=1纔會使用緩存,如果id爲其他值將不使用緩存。
unless條件
condition是在調用方法之前判斷條件,決定是否緩存。unless是在調用方法之後判斷條件,決定是否不緩存。
@GetMapping("/find")
@Cacheable(cacheNames = "hello",unless="#result.id.contains('1')" )
public User find(String id) {
System.out.println("從數據庫查詢數據");
User user = new User();
user.setId(id);
return user;
}
- unless:如果SpEL條件成立,則不緩存。
- #result.id.contains:result指方法return的數據,id指return的user的id參數,contains指id的值是否包含'1',如果包含則unless條件成立,不進行緩存。
caffeine
spring boot支持多種不同的緩存供應商。在默認情況下使用的是簡單緩存,不建議在正式環境使用。我們可以配置一些更加強大的緩存,比如Hibernate的默認緩存EhCache等,而caffeine則是基於java8新出的一個高性能緩存,官方稱其接近完美。下面就來介紹在spring boot中集成caffeine。
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
在pom.xml中增加以上依賴,spring boot就會自動用caffeine替換默認的簡單緩存,用法都是一樣的。
properties參數配置
spring.cache.type=caffeine
spring.cache.cache-names=hello,world
spring.cache.caffeine.spec=maximumSize=1,expireAfterAccess=5s
- spring.cache.type:指定使用哪個緩存供應商
- spring.cache.cache-names:在啓動時創建緩存名稱,即前面的cacheNames,多個名稱用逗號分隔。
- spring.cache.caffeine.spec:這是caffeine緩存的專用配置。
- maximumSize=1:最大緩存數量,假如有緩存1,再寫入緩存2時,就有2個緩存,超出最大數量,緩存1就會被清除。
- expireAfterAccess=5s:緩存5秒,即緩存在5秒之內沒有被使用,就會被清除。
默認情況下,緩存的數據會一直保存在內存中,有些數據可能用一次後很長時間都不會再用,這樣會有大量無用的數據長時間佔用內存,通過配置properties可以及時清除不需要的緩存。