1. 程式人生 > >SpringBoot系列之快取使用教程

SpringBoot系列之快取使用教程

介紹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