SpringBoot系列之快取使用教程
阿新 • • 發佈:2020-04-04
介紹SpringBoot專案中使用快取,之前先介紹一下Spring的快取抽象和JSR107,本部落格是我在學習尚矽谷視訊和參考其它部落格之後做的筆記,僅供學習參考
@[toc]
## 一、Spring的快取抽象
### 1.1、快取抽象定義
Spring從3.1開始定義了org.springframework.cache.Cache
和org.springframework.cache.CacheManager介面來統一不同的快取技術;並支援使用Java Caching(JSR-107)註解簡化我們進行快取開發。Spring Cache 只負責維護抽象層,具體的實現由你的技術選型來決定。將快取處理和快取技術解除耦合。
### 1.2、重要介面
* Cache:快取抽象的規範介面,快取實現有:RedisCache、EhCacheCache、ConcurrentMapCache等
* CacheManager:快取管理器,管理Cache的生命週期
## 二、JSR107
### 2.1、JSR107核心介面
Java Caching(JSR-107)定義了5個核心介面,分別是CachingProvider, CacheManager, Cache, Entry和 Expiry。
* CachingProvider:建立、配置、獲取、管理和控制多個CacheManager
* CacheManager:建立、配置、獲取、管理和控制多個唯一命名的Cache,Cache存在於CacheManager的上下文中。一個CacheManager僅對應一個CachingProvider
* Cache:是由CacheManager管理的,CacheManager管理Cache的生命週期,Cache存在於CacheManager的上下文中,是一個類似map的資料結構,並臨時儲存以key為索引的值。一個Cache僅被一個CacheManager所擁有
* Entry:是一個儲存在Cache中的key-value對
* Expiry:每一個儲存在Cache中的條目都有一個定義的有效期。一旦超過這個時間,條目就自動過期,過期後,條目將不可以訪問、更新和刪除操作。快取有效期可以通過ExpiryPolicy設定
### 2.2、JSR107圖示
引用尚矽谷視訊課件中的圖示:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200331181533420.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ0MjczOTE=,size_16,color_FFFFFF,t_70)
## 三、Spring快取使用
### 3.1、重要註解簡介
例子實踐之前,先簡單介紹Spring提供的重要快取註解
* @Cacheable:針對方法配置,能夠根據方法的請求引數對其結果進行快取
* @CacheEvict:清空快取
* @CachePut:既呼叫方法,又更新快取資料
* @EnableCaching:開啟基於註解的快取
* @Caching:定義複雜的快取規則
### 3.2、環境準備
ok,本部落格以尚矽谷視訊例子進行改寫,用這個比較經典的例子進行說明
環境準備:
* maven環境
* IntelliJ IDEA
新建兩張表:
```sql
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`lastName` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`gender` int(2) DEFAULT NULL,
`d_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```
```sql
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`departmentName` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```
### 3.3、引入spring-boot-starter-cache模組
```xml
```
### 3.4、主要註解例子實踐
#### 3.4.1、@EnableCaching
@EnableCaching開啟基於註解的快取
```java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class SpringbootCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootCacheApplication.class, args);
}
}
```
#### 3.4.2、@Cacheable註解
@Cacheable註解的作用,前面也簡介了,主要是針對方法配置,能夠根據方法的請求引數對其結果進行快取,介紹一下註解的主要屬性
* cacheNames/value:指定快取元件的名字,陣列形式
* key:快取資料使用的key,確定快取可以用唯一key進行指定;eg:編寫SpEL; #id,引數id的值 ,,#a0(第一個引數), #p0(和a0的一樣的意義) ,#root.args[0]
* keyGenerator:key的生成器;可以自己指定key的生成器的元件id(注意: key/keyGenerator:二選一使用;不能同時使用)
* cacheManager:指定快取管理器;或者cacheResolver指定獲取解析器
* condition:指定符合條件的情況下才快取;使用SpEl表示式,eg:condition = "#a0>1":第一個引數的值>1的時候才進行快取
* unless:否定快取;當unless指定的條件為true,方法的返回值就不會被快取;eg:unless = "#a0!=2":如果第一個引數的值不是2,結果不快取;
* sync:是否使用非同步模式
```java
@Cacheable(value = {"emp"}, /*keyGenerator = "myKeyGenerator",*/key = "#id",condition = "#a0>=1",unless = "#a0!=2")
public Employee getEmp(Integer id) {
Employee employee = this.employeeMapper.getEmpById(id);
LOG.info("查詢{}號員工資料",id);
return employee;
}
```
這裡也可以使用自定義的keyGenerator,使用屬性keyGenerator = "myKeyGenerator
定義一個@Bean類,將KeyGenerator新增到Spring容器
```java
@Configuration
public class CacheConfig {
@Bean(value = {"myKeyGenerator"})
public KeyGenerator keyGenerator(){
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
return method.getName()+"["+ Arrays.asList(params).toString()+"]";
}
};
}
}
```
#### 3.4.3、@CachePut註解
@CachePut註解也是一個用來快取的註解,不過快取和@Cacheable有明顯的區別是即呼叫方法,又更新快取資料,也就是執行方法操作之後再來同步更新快取,所以這個主鍵常用於更新操作,也可以用於查詢,主鍵屬性和@Cacheable有很多類似的,詳情參看@link @CachePut原始碼
```java
/**
* @CachePut:既呼叫方法,又更新快取資料;同步更新快取
* 修改了資料,同時更新快取
*/
@CachePut(value = {"emp"}, key = "#result.id")
public Employee updateEmp(Employee employee){
employeeMapper.updateEmp(employee);
LOG.info("更新{}號員工資料",employee.getId());
return employee;
}
```
#### 3.4.4、 @CacheEvic註解
主要屬性:
* key:指定要清除的資料
* allEntries = true:指定清除這個快取中所有的資料
* beforeInvocation = false:預設代表快取清除操作是在方法執行之後執行
* beforeInvocation = true:代表清除快取操作是在方法執行之前執行
```java
@CacheEvict(value = {"emp"}, beforeInvocation = true,key="#id")
public void deleteEmp(Integer id){
employeeMapper.deleteEmpById(id);
//int i = 10/0;
}
```
#### 3.4.5、@Caching註解
@Caching 用於定義複雜的快取規則,可以整合@Cacheable和 @CachePut
```java
// @Caching 定義複雜的快取規則
@Caching(
cacheable = {
@Cacheable(/*value={"emp"},*/key = "#lastName")
},
put = {
@CachePut(/*value={"emp"},*/key = "#result.id"),
@CachePut(/*value={"emp"},*/key = "#result.email")
}
)
public Employee getEmpByLastName(String lastName){
return employeeMapper.getEmpByLastName(lastName);
}
```
#### 3.4.6、 @CacheConfig註解
@CacheConfig註解可以用於抽取快取的公共配置,然後在類加上就可以,eg:`@CacheConfig(cacheNames = {"emp"},cacheManager = "employeeCacheManager")`
**附錄拓展:SpEL表示式用法**
Cache SpEL available metadata
|名稱 |位置 |描述 |示例 |
|-------------|-------------------------|------------------------------------------------------------------|--------------------|
|methodName |root物件 |當前被呼叫的方法名 |#root.methodname |
|method |root物件 |當前被呼叫的方法 |#root.method.name |
|target |root物件 |當前被呼叫的目標物件例項 |#root.target |
|targetClass |root物件 |當前被呼叫的目標物件的類 |#root.targetClass |
|args |root物件 |當前被呼叫的方法的引數列表 |#root.args[0] |
|caches |root物件 |當前方法呼叫使用的快取列表 |#root.caches[0].name|
|argument Name|執行上下文(avaluation context)|當前被呼叫的方法的引數,如findArtisan(Artisan artisan),可以通過#artsian.id獲得引數 |#artsian.id |
|result |執行上下文(evaluation context)|方法執行後的返回值(僅當方法執行後的判斷有效,如 unless cacheEvict的beforeInvocation=false)|#result |
## 四、整合Redis快取
### 4.1、環境準備
基於前面的Spring快取環境,整合redis要引入相關配置:
```bash
```
切換快取方式為Redis:`spring.cache.type=redis`
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200402173831209.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ0MjczOTE=,size_16,color_FFFFFF,t_70)
### 4.2、Redis配置類實現
RedisTemplate配置
```java
@Resource
private LettuceConnectionFactory lettuceConnectionFactory;
@Bean
@Primary
public Redis