Spring緩存註解
緩存你們應該不會陌生吧,像你們熟知的redis、memcached都是如今所流行的用與緩存數據的nosql,叫nosql的緣由在於他們不是像咱們jpa那樣將數據存到磁盤中,他們主要是將數據存到內存中,而後咱們訪問數據的時候直接從內存加載出來,經過這樣的方法來提升咱們程序的運行效率。至於redis等他們具體如何運轉的我就不一一介紹了.。
若是咱們作web開發的話,那麼應該都會接觸到spring的東西,正是由於有spring的存在,才使咱們的開發效率更快,而咱們本節主要講的就是基於spring幫咱們實現的緩存註解。
咱們回想一下,在咱們平常的開發中,其實咱們所作的後臺其實大多對數據的操做,而咱們操做的數據基本上都是須要存到jpa數據庫中,咱們前端顯示的時候就要經過查詢數據庫來將數據查詢出來並傳送給前端。若是併發小的話,其實咱們是無需關注這個事情,可是若是你的併發量很大的時候,你頻繁的訪問數據庫,這個開銷是很大的,而在咱們平常開發的項目中,實際上是讀取數據的頻率是大於寫的頻率的,那麼咱們爲什麼不將讀取的數據放到緩存中,而後下一次查詢的時候,會先去緩存查看是否有數據,若是沒有的話在去查詢數據庫。這樣的話,一些共有的數據是否是你們訪問的話就不會一一查詢數據庫了,其次是由於從內存中讀取數據是遠遠快於磁盤讀取的。固然,這種緩存的工具,spring也已經幫咱們整合好了。而接下來也會基於如下幾個註解來說是如何進行緩存的。前端
@Cacheable
@CachePut
@CacheEvict
@Caching
@Cacheable
這個註解的做用是負責將返回的數據進行緩存,當咱們第一次訪問的時候,會將查出來的數據先緩存到redis中,當以後再發起訪問的時候,會先去查看緩存中是否存在該條數據,若是存在的話就直接從緩存拿取該條數據。他裏面有這幾個參數java
首先是value,這個做用是什麼,其實就是至關於咱們取的名字,好比你的緩存取名叫test,那麼你在redis緩存裏面就會存一個tes名稱爲test的緩存,而後你查詢出來的數據就是放在這個test下面,下次經過這個value去緩存中找,若是找到就直接拿取,沒找到就去數據庫查並將數據放入緩存中,緩存的key就是這個的value,緩存中的value就是咱們查詢的返回數據。
第二個參數key:這個是什麼呢?舉個列子,咱們經過用戶id來獲取用戶的數據,好比a用戶存的是test的話,那麼b用戶也是經過這個方法去訪問數據庫的,可是緩存中已經有數據了,這時候b用戶就不會去數據庫拿取數據,直接從緩存讀,可是緩存存的是a用戶的數據,那不是亂套了嗎,因此key就至關於子文件夾,好比咱們的方法以下所示mysql
Object zjtest(long id);
若是咱們加了緩存的話,那麼id就能夠爲key,這樣的話咱們的a用戶訪問數據的時候,就會在緩存生成一個test.a的key和value,而b用戶去訪問的時候就會去緩存中查詢test.b的緩存,可是沒有這條數據,因此b就會去數據庫拿取數據在緩存,這樣就達到不一樣的用戶緩存不一樣的數據。其實用個最好理解的方式就是test至關於一個文件夾,而a、b、c其實就至關於子文件夾。web
第三個參數condition其實就是一種判斷的條件,就至關於咱們的if,若是爲true就緩存,不爲true就不緩存。redis
@CachePut
這個註解的做用就其實有點相似於上面的,只是他的做用至關於咱們數據庫中的update的做用,加上這個註解後,咱們每次訪問數據都不會從緩存中拿取數據,而是直接經過去數據庫查詢並將數據緩存到redis中。可能有人會問,這樣有什麼做用呢?其實若是你是結合到cachable就有做用了,由於咱們更新後數據是否是變化了,因此咱們就須要將以前的數據的給清空掉,不然的話就會產生髒數據。
一樣他也有幾個參數須要填寫,其實就和cachable同樣的
spring
這幾個參數的意義和上面咱們講的同樣,因此就不在說了sql
@CacheEvict
咱們上面的put的註解說了他是用於更新的,那麼若是咱們增長了數據或者刪除了數據怎麼辦,好比經過用戶id來查詢用戶所購買的全部東西的數據,若是用戶又買了新東西或者刪除了某個物品的信息,那麼咱們怎麼辦,理論上咱們是可使用上面的註解,但是咱們刪除和增長其實沒有必要去查詢新數據。因此咱們這個CacheEvict註解的做用就出現了。他的做用其實就是幫咱們清空指定的緩存,他能夠清空value,也能夠清空value.key的數據。這樣的話咱們能夠針對性的去處理數據。
數據庫
仍是和以前同樣前面三個參數就不說了,咱們直接從第四個提及allEntries的做用其實就是調用方法後當即清空緩存,若是false的話就是不清空。數組
beforeinvocation 主要的做用是在方法執行後仍是執行請清空,一般咱們使用allentries,由於成功後咱們才清空數據。
緩存
@Caching
最後一個註解的做用是啥呢?咱們已經將了基本的,這個註解的做用就是聯合使用。看源碼就知道
他接收的是一個數組,以及put、able、evict等參數。那麼這個註解何時會用到呢?舉個例子,若是咱們的方法操作了多個表數據的時候,咱們就須要多個緩存。好比要同時清空a和b的用戶的數據,那麼就須要使用caching來鏈接
@Caching(evict = {@CacheEvict(valie= "id", key = "#uuid"), @CacheEvict(value= {"list", "other"}, allEntries = true)})
其實就是上面的這種配置方法。
如何將咱們的項目整合進去呢:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 引入mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.11</version> </dependency> </dependencies>
而後啓用這個配置
@Configuration @EnableCaching//啓用緩存,這個註解很重要; public class RedisCacheConfig extends CachingConfigurerSupport { /** * 緩存管理器. * @param redisTemplate * @return */ @Bean public CacheManager cacheManager(RedisTemplate<?,?> redisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); cacheManager.setDefaultExpiration(60*60);//設置緩存的時間 return cacheManager; } /** * RedisTemplate緩存操做類,相似於jdbcTemplate的一個類; * * 雖然CacheManager也能獲取到Cache對象,可是操做起來沒有那麼靈活; * * 這裏在擴展下:RedisTemplate這個類不見得很好操做,咱們能夠在進行擴展一個咱們 * * 本身的緩存類,好比:RedisStorage類; * * @param factory : 經過Spring進行注入,參數在application.properties進行配置; * @return */ @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>(); redisTemplate.setConnectionFactory(factory); //key序列化方式;(否則會出現亂碼;),可是若是方法上有Long等非String類型的話,會報類型轉換錯誤; //因此在沒有本身定義key生成策略的時候,如下這個代碼建議不要這麼寫,能夠不配置或者本身實現ObjectRedisSerializer //或者JdkSerializationRedisSerializer序列化方式; RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long類型不能夠會出現異常信息; redisTemplate.setKeySerializer(redisSerializer); redisTemplate.setHashKeySerializer(redisSerializer); redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return redisTemplate; }