在上一篇文章(《SpringBoot(二十四)整合Redis》)中,已經實現了Spring Boot對Redis的整合,既然已經講到Cache了,今天就介紹介紹緩存注解。各家互聯網產品現在數據量越來越大,其快速增長造成網絡擁塞和服務器超載,導致客戶訪問延遲增大,服務質量日益顯現出來。緩存技術被認為是減輕服務器負載、降低網絡擁塞、增強可擴展性的有效途徑之一。
v概念介紹
Spring為我們提供了幾個注解來支持Spring Cache。其核心主要是@Cacheable和@CacheEvict。使用@Cacheable標記的方法在執行后Spring Cache將緩存其返回結果,而使用@CacheEvict標記的方法會在方法執行前或者執行后移除Spring Cache中的某些元素。下面我們將來詳細介紹一下Spring基於注解對Cache的支持所提供的幾個注解。
Spring Cache常見概念介紹
| 名稱 | 解釋 |
|---|---|
| Cache | 緩存接口,定義緩存操作。實現有:RedisCache、EhCacheCache、ConcurrentMapCache等 |
| CacheManager | 緩存管理器,管理各種緩存(cache)組件 |
| @Cacheable | 主要針對方法配置,能夠根據方法的請求參數對其進行緩存 |
| @CacheEvict | 清空緩存 |
| @CachePut | 保證方法被調用,又希望結果被緩存。 與@Cacheable區別在於是否每次都調用方法,常用於更新 |
| @EnableCaching | 開啟基於注解的緩存 |
| keyGenerator | 緩存數據時key生成策略 |
| serialize | 緩存數據時value序列化策略 |
| @CacheConfig | 統一配置本類的緩存注解的屬性 |
注解(@Cacheable/@CachePut/@CacheEvict)的主要參數
| 名稱 | 解釋 | example |
|---|---|---|
| value | 緩存的名稱,在 spring 配置文件中定義,必須指定至少一個 | e.g. @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”} |
| key | 緩存的 key,可以為空,如果指定要按照 SpEL 表達式編寫, 如果不指定,則缺省按照方法的所有參數進行組合 |
e.g. @Cacheable(value=”testcache”,key=”#id”) |
| condition | 緩存的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false, 只有為 true 才進行緩存/清除緩存 |
e.g.@Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
| unless | 否定緩存。當條件結果為TRUE時,就不會緩存。 | e.g.@Cacheable(value=”testcache”,unless=”#userName.length()>2”) |
| allEntries (@CacheEvict ) |
是否清空所有緩存內容,缺省為 false,如果指定為 true, 則方法調用后將立即清空所有緩存 |
e.g. @CachEvict(value=”testcache”,allEntries=true) |
| beforeInvocation (@CacheEvict) |
是否在方法執行前就清空,缺省為 false,如果指定為 true, 則在方法還沒有執行的時候就清空緩存,缺省情況下,如果方法 執行拋出異常,則不會清空緩存 |
e.g. @CachEvict(value=”testcache”,beforeInvocation=true) |
v准備工作
1.1 引入依賴pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
激活啟動類注解@EnableCaching

v實戰演練
2.1 添加service層
package com.demo.service; import com.demo.pojo.UserDetails; /** * Created by toutou on 2019/1/20. */ public interface CacheService { UserDetails getUserDetailsByUid(int uid); UserDetails updateUserInfo(UserDetails userDetails); int delUserInfoById(int uid); }
package com.demo.service; import com.demo.dao.UserDetailsMapper; import com.demo.pojo.UserDetails; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; /** * Created by toutou on 2019/1/20. */ @Service public class CacheServiceImpl implements CacheService{ @Autowired UserDetailsMapper userDetailsMapper; @Override @Cacheable(value = "user_details", key = "#uid", unless="#result == null") public UserDetails getUserDetailsByUid(int uid){ System.out.println(" Cacheable 有請求過來了"); UserDetails userDetails = userDetailsMapper.getUserDetailsByUid(uid); return userDetails; } @Override @CachePut(value = "user_details", key = "#user.id") public UserDetails updateUserInfo(UserDetails user){ System.out.println(" CachePut 有請求過來了"); if(userDetailsMapper.updateByPrimaryKeySelective(user) > 0) { // 這里也可以直接在updateByPrimaryKeySelective的方法里,修改后直接查詢出該記錄返回UserDetails實例,看需求。 user = userDetailsMapper.getUserDetailsByUid(user.getId()); return user; }else{ return null; } } @Override @CacheEvict(value = "user_details", key = "#uid") public int delUserInfoById(int uid){ System.out.println(" CacheEvict 有請求過來了"); return userDetailsMapper.deleteByPrimaryKey(uid); } }
unless="#result == null"是指當查詢為空時,不緩存,默認是空也會緩存。
2.2 添加CacheController
package com.demo.controller; import com.demo.pojo.UserDetails; import com.demo.service.CacheService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Created by toutou on 2019/1/20. */ @RestController @Slf4j public class CacheController { @Autowired CacheService cacheService; @RequestMapping(value = "/cache/getuserbyid") public UserDetails getUserDetailsByUid(int uid){ try { return cacheService.getUserDetailsByUid(uid); }catch (Exception e){ System.out.println(e.toString()); return null; } } @RequestMapping(value = "/cache/updateuserinfo") public int updateUserInfo(int uid, String city){ UserDetails userDetails = new UserDetails(); userDetails.setId(uid); userDetails.setCity(city); userDetails = cacheService.updateUserInfo(userDetails); return userDetails == null ? 0 : userDetails.getUid(); } @RequestMapping(value = "/cache/deluserinfobyid") public int delUserInfoById(int uid){ return cacheService.delUserInfoById(uid); } }
2.3 實現Serializable接口

v效果展示
3.1 Cacheable效果
當我們本地請求http://localhost:8081/cache/getuserbyid?uid=5接口時,可以看到控制台輸出Cacheable 有請求過來了,而后續再次請求該接口時,不會再輸出Cacheable 有請求過來了,這是因為直接走了緩存機制了,CacheServiceImpl的方法不再被調用。

通過Redis可以看到,user_details::5的記錄已被創建。

3.2 CachePut效果
當我們本地請求http://localhost:8081/cache/updateuserinfo?uid=5&city=首都 接口時,將更新數據庫和Redis中對應的字段值。

查詢接口,更新成功。控制台再次輸出Cacheable 有請求過來了

3.3 CacheEvict效果
當我們本地請求http://localhost:8081/cache/deluserinfobyid?uid=5 接口時,將刪除數據中和Redis中的數據。

v博客總結
Redis和@Cacheable、@CachePut、@CacheEvict結合使用,效果挺好,結合這篇和上篇文章(《SpringBoot(二十四)整合Redis》),可以嘗試着結合使用試試。
v源碼地址
https://github.com/toutouge/javademosecond/tree/master/hellospringboot
作 者:請叫我頭頭哥
出 處:http://www.cnblogs.com/toutou/
關於作者:專注於基礎平台的項目開發。如有問題或建議,請多多賜教!
版權聲明:本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
特此聲明:所有評論和私信都會在第一時間回復。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信我
聲援博主:如果您覺得文章對您有幫助,可以點擊文章右下角【推薦】一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!
