Spring緩存注解


Spring緩存注解
  緩存大家應該不會陌生吧,像大家熟知的redis、memcached都是現在所流行的用與緩存數據的nosql,叫nosql的原因在於他們不是像我們jpa那樣將數據存到磁盤中,他們主要是將數據存到內存中,然后我們訪問數據的時候直接從內存加載出來,通過這樣的方法來提高我們程序的運行效率。至於redis等他們具體如何運轉的我就不一一介紹了.。
  如果我們做web開發的話,那么應該都會接觸到spring的東西,正是因為有spring的存在,才使我們的開發效率更快,而我們本節主要講的就是基於spring幫我們實現的緩存注解。
  我們回想一下,在我們日常的開發中,其實我們所做的后台其實大多對數據的操作,而我們操作的數據基本上都是需要存到jpa數據庫中,我們前端顯示的時候就要通過查詢數據庫來將數據查詢出來並傳送給前端。如果並發小的話,其實我們是無需關注這個事情,但是如果你的並發量很大的時候,你頻繁的訪問數據庫,這個開銷是很大的,而在我們日常開發的項目中,其實是讀取數據的頻率是大於寫的頻率的,那么我們為何不將讀取的數據放到緩存中,然后下一次查詢的時候,會先去緩存查看是否有數據,如果沒有的話在去查詢數據庫。這樣的話,一些共有的數據是不是大家訪問的話就不會一一查詢數據庫了,其次是因為從內存中讀取數據是遠遠快於磁盤讀取的。當然,這種緩存的工具,spring也已經幫我們整合好了。而接下來也會基於以下幾個注解來講是如何進行緩存的。

@Cacheable
@CachePut
@CacheEvict
@Caching
@Cacheable
  這個注解的作用是負責將返回的數據進行緩存,當我們第一次訪問的時候,會將查出來的數據先緩存到redis中,當之后再發起訪問的時候,會先去查看緩存中是否存在該條數據,如果存在的話就直接從緩存拿取該條數據。他里面有這幾個參數


首先是value,這個作用是什么,其實就是相當於我們取的名字,比如你的緩存取名叫test,那么你在redis緩存里面就會存一個tes名稱為test的緩存,然后你查詢出來的數據就是放在這個test下面,下次通過這個value去緩存中找,如果找到就直接拿取,沒找到就去數據庫查並將數據放入緩存中,緩存的key就是這個的value,緩存中的value就是我們查詢的返回數據。
第二個參數key:這個是什么呢?舉個列子,我們通過用戶id來獲取用戶的數據,比如a用戶存的是test的話,那么b用戶也是通過這個方法去訪問數據庫的,但是緩存中已經有數據了,這時候b用戶就不會去數據庫拿取數據,直接從緩存讀,但是緩存存的是a用戶的數據,那不是亂套了嗎,所以key就相當於子文件夾,比如我們的方法如下所示

Object zjtest(long id);


如果我們加了緩存的話,那么id就可以為key,這樣的話我們的a用戶訪問數據的時候,就會在緩存生成一個test.a的key和value,而b用戶去訪問的時候就會去緩存中查詢test.b的緩存,但是沒有這條數據,所以b就會去數據庫拿取數據在緩存,這樣就達到不同的用戶緩存不同的數據。其實用個最好理解的方式就是test相當於一個文件夾,而a、b、c其實就相當於子文件夾。

第三個參數condition其實就是一種判斷的條件,就相當於我們的if,如果為true就緩存,不為true就不緩存。


@CachePut
這個注解的作用就其實有點類似於上面的,只是他的作用相當於我們數據庫中的update的作用,加上這個注解后,我們每次訪問數據都不會從緩存中拿取數據,而是直接通過去數據庫查詢並將數據緩存到redis中。可能有人會問,這樣有什么作用呢?其實如果你是結合到cachable就有作用了,因為我們更新后數據是不是變化了,所以我們就需要將之前的數據的給清空掉,否則的話就會產生臟數據。
同樣他也有幾個參數需要填寫,其實就和cachable一樣的


這幾個參數的意義和上面我們講的一樣,所以就不在說了

 

@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;  
    }  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM