SpringBoot 學習之緩存開發

緩存在開發中是一個必不可少的優化點,近期在項目重構中,有關緩存問題,花費大量的時間去作優化,好比在加載數據比較所的場景中,使用緩存機制來提升接口的響應速度,間接的提升用戶體驗。對於緩存,不少開發者對它都是既愛又恨,愛它的是:可以大幅度提高響應效率,恨的是:若是緩存處理很差、沒有用好緩存策略,沒有及時更新數據庫的數據就會致使數據產生滯後,從而致使用戶體驗較差。這是一個很嚴重的老大難的問題,例如我在開發某項功能須要和其餘項目進行對接的時候,線上老是出現我推送接口數據成功可是網站數據滯後的現象,詢問對方的技術人員,獲得的回覆是緩存問題,只要刪除緩存就沒事了,我只能無奈了……全部說如何處理好緩存,對於咱們開發人員來講,是一個極其棘手的問題。值得慶幸的是,SpringBoot已經提供給開發者很便捷的開發工做,廢話很少了,接下來開始探索SpringBoot的緩存如何使用吧!java

  Spring 從3.1 版本開始就定義了 org.springframework.cache.Cacheorg.springframework.cache.CacheManager 接口來統一不一樣的緩存技術,Cache 接口下 Spring 提供了各類的xxxCache的實現,例如RedisCache、EhCacheCache、ConcurrentMapCache等。每次調用須要緩存功能的方法時,Spring會檢查檢查指定參數的指定的目標方法是否已經被調用過。若是有就直接從緩存中獲取方法調用後的結果,若是沒有就調用方法並緩存結果後返回給用戶,下次調用直接從緩存中獲取。mysql

重要概念以及緩存註解

緩存註解

名稱 解釋
Cache 緩存接口,定義緩存操做。實現有:RedisCache、EhCacheCache、ConcurrentMapCache等
CacheManager 緩存管理器,管理各類緩存(cache)組件
@Cacheable 主要針對方法配置,可以根據方法的請求參數對其進行緩存。主要實現的功能在進行一個讀操做的時候,先從緩存中查詢,若是查找不到,在讀取數據庫。這是緩存的註解最重要的一個方法,基本上咱們的全部緩存實現都要依賴於它
@CacheEvict 主要是配合@Cacheable一塊兒使用的,它的主要做用就是清除緩存。當方法進行一些更新、刪除操做的時候,就須要刪除緩存
@CachePut 這個註解它老是會把數據緩存,而不會去每次作檢查它是否存在 。與@Cacheable區別在因而否每次都調用方法,經常使用於更新
@EnableCaching 開啓基於註解的緩存,主要做用就是全局配置緩存
keyGenerator 緩存數據時key生成策略
serialize 緩存數據時value序列化策略
@CacheConfig 統一配置本類的緩存註解的屬性

@Cacheable/@CachePut/@CacheEvict 主要的參數

名稱 解釋
value 緩存的名稱,在 spring 配置文件中定義,必須指定至少一個。例如:  @Cacheable(value=」mycache」) 或者@Cacheable(value={」cache1」,」cache2」}
key 緩存的 key,能夠爲空,若是指定要按照 SpEL 表達式編寫,若是不指定,則缺省按照方法的全部參數進行組合。例如:@Cacheable(value=」testcache」,key=」#id」)
condition 緩存的條件,能夠爲空,使用 SpEL 編寫,返回 true 或者 false,只有爲 true 才進行緩存/清除緩存。@Cacheable(value=」testcache」,condition=」#userName.length()>2」)
unless 否認緩存。當條件結果爲TRUE時,就不會緩存。@Cacheable(value=」testcache」,unless=」#userName.length()>2」)
allEntries(@CacheEvict ) 是否清空全部緩存內容,缺省爲 false,若是指定爲 true,則方法調用後將當即清空全部緩存。  @CachEvict(value=」testcache」,allEntries=true)
beforeInvocation(@CacheEvict) 是否在方法執行前就清空,缺省爲 false,若是指定爲 true,則在方法尚未執行的時候就清空緩存,缺省狀況下,若是方法執行拋出異常,則不會清空緩存@CachEvict(value=」testcache」,beforeInvocation=true)

springBoot開啓註解

開始使用前須要導入依賴

<!-- Springboot devtools熱部署配置 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
	<optional>true</optional>
</dependency>

<!-- 引入lombok 依賴 -->
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<scope>provided</scope>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<scope>provided</scope>
</dependency>

<!-- 引入cache 緩存依賴 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<!--MySQL依賴 -->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>

<!-- 引入 MyBatis依賴 -->
<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>1.3.2</version>
</dependency>

在啓動類註解@EnableCaching開啓緩存

@SpringBootApplication
@EnableCaching  //開啓緩存
public class CacheApplication{

    public static void main(String[] args) {
        SpringApplication.run(CacheApplication.class, args);
    }

}

緩存@Cacheable

@Cacheable註解會先查詢是否已經有緩存,有會使用緩存,沒有則會執行方法並緩存web

@Cacheable(key = "#id", unless = "#result.state==0")
public list<SysUser> getLists(Integer uid){
    return cacheDao.getListsByUid(uid);
}

到這裏,能夠運行程序檢驗緩存功能是否實現了。若有興趣的話,也能夠深刻源碼,查看其餘的屬性,這裏簡單的說下。spring

String[] cacheNames() default {}; //和value註解差很少,二選一

String keyGenerator() default ""; //key的生成器。key/keyGenerator二選一使用

String cacheManager() default ""; //指定緩存管理器

String cacheResolver() default ""; //或者指定獲取解析器

String condition() default ""; //條件符合則緩存

String unless() default ""; //條件符合則不緩存

boolean sync() default false; //是否使用異步模式

配置@CacheConfig

當咱們須要緩存的地方愈來愈多,你可使用@CacheConfig(cacheNames = {"myCache"})註解來統一指定value的值,這時可省略value,若是你在你的方法依舊寫上了value,那麼依然以方法的value值爲準。sql

@Service
@CacheConfig(cacheNames = "articleCache")
public class ArticleService {
    ……
}

CacheConfig 的屬性數據庫

String keyGenerator() default "";  //key的生成器。key/keyGenerator二選一使用

String cacheManager() default "";  //指定緩存管理器

String cacheResolver() default ""; //或者指定獲取解析器

更新@CachePut

@CachePut註解的做用 主要針對方法配置,可以根據方法的請求參數對其結果進行緩存,和 @Cacheable 不一樣的是,它每次都會觸發真實方法的調用 。簡單來講就是用戶更新緩存數據。但須要注意的是該註解的value 和 key 必須與要更新的緩存相同,也就是與@Cacheable 相同。示例:緩存

@CachePut(value = "cacheTemp", key = "targetClass + #p0")
public SysUser updata(SysUser sysUser) {
    SysUser sysUser = sysUserDao.findAllById(sysUser.getId());
    sysUserDao.updata(sysUser);
    return sysUser;
}

@Cacheable(value = "cacheTemp", key = "targetClass +#p0")//清空緩存
public SysUser save(SysUser sysUser) {
    sysUserDao.save(sysUser);
    return sysUser;
}

CachePut 其餘的屬性mybatis

String[] cacheNames() default {}; //與value二選一

String keyGenerator() default "";  //key的生成器。key/keyGenerator二選一使用

String cacheManager() default "";  //指定緩存管理器

String cacheResolver() default ""; //或者指定獲取解析器

String condition() default ""; //條件符合則緩存

String unless() default ""; //條件符合則不緩存

清除@CacheEvict

@CachEvict 的做用 主要針對方法配置,可以根據必定的條件對緩存進行清空 。less

@Cacheable(value = "cacheTemp",key = "#id")
public SysUser save(SysUser job) {
    ……
}

//清除一條緩存,key爲要清空的數據
@CacheEvict(value="cacheTemp",key="#id")
public void delect(int id) {
    ……
}

//方法調用後清空全部緩存
@CacheEvict(value="accountCache",allEntries=true)
public void delectAll() {
    ……
}

//方法調用前清空全部緩存
@CacheEvict(value="accountCache",beforeInvocation=true)
public void delectAll() {
    ……
}

其餘屬性異步

String[] cacheNames() default {}; //與value二選一

String keyGenerator() default "";  //key的生成器。key/keyGenerator二選一使用

String cacheManager() default "";  //指定緩存管理器

String cacheResolver() default ""; //或者指定獲取解析器

String condition() default ""; //條件符合則清空

測試

這裏使用postman模擬接口請求

執行插入操做

首先咱們來增長一篇文章:請求add接口

後臺返回表示成功:

從後臺數據庫看到已經插入數據,它的id是1

執行查詢操做

在查詢操做中,getArticle,我使用線程睡眠的方式,模擬了5秒的時間來處理耗時性業務,第一次請求確定會查詢數據庫,理論上第二次請求,將會走緩存,咱們來測試一下:首先執行查詢操做

接口響應成功,再看一下後臺打印:表示執行了一次查詢操做,耗時5212秒

好,重點來了,咱們再次請求接口看看會返回什麼?

與上面的比對,此次沒有打印執行數據庫查詢操做,證實沒有走數據庫,而且耗時只有3ms,成功了!緩存發揮做用,從5212秒減少到3秒!大大提高了響應速度,

執行更新操做

當咱們進行修改操做的時候,咱們但願緩存的數據被清空:

後臺控制檯打印:

接下來,連續請求三次請求查詢接口,看看會返回什麼?

第一次請求以及結果

連續三次調用查詢接口,雖然每次返回的都是相同的結果,看上去沒有什麼不一樣,可是我卻有很明顯的感覺,就是第一次查詢最慢,第二次、第三次查詢特別快。第一次查詢耗時是5063毫秒,第二次、第三次耗時確實0,這是由於當咱們第一次執行id=2的數據庫查詢操做,那個時候緩存已被清空,是從數據庫中獲取的最新數據並放進緩存,而後後面的幾回查詢都是直接從緩存中獲取數據,因此查詢速度很快。

執行刪除操做

在刪除操做中,執行了一次刪除,那麼緩存也會被清空,查詢的時候會再次走數據庫,這裏就不在具體展現了。

總結

如何在開發中使用緩存?怎樣合理的使用都是值得咱們學習的地方,緩存能大大提高程序的響應速度,提高用戶體驗,不過它適用的場景也是讀多寫少的業務場景,若是數據頻繁修改,緩存將會失去意義,每次仍是執行的數據庫操做!這裏只是探討了Spring的註解緩存,相對來講仍是比較簡單的,但願起到拋磚引玉的做用.

相關文章
相關標籤/搜索