天天看點

springboot與緩存(整合redis)一、什麼是緩存二、Spring緩存抽象三、幾個重要概念&緩存注解四、springboot整合redis實作緩存五、@Cacheable注解六、@CachePut七、@CacheEvict八、@Caching

一、什麼是緩存

緩存就是資料交換的緩沖區(稱作:Cache),他把一些外存上的資料儲存在記憶體上,為什麼儲存在記憶體上,我們運作的所有程式裡面的變量都是存放在記憶體中的,是以如果想将值放入記憶體上,可以通過變量的方式存儲。在JAVA中一些緩存一般都是通過Map集合來實作的。

緩存在不同的場景下,作用是不一樣的具體舉例說明:

✔  作業系統磁盤緩存 ——> 減少磁盤機械操作。
     ✔  資料庫緩存——>減少檔案系統IO。
     ✔  應用程式緩存——>減少對資料庫的查詢。
     ✔  Web伺服器緩存——>減少應用伺服器請求。
     ✔  用戶端浏覽器緩存——>減少對網站的通路。
           

具體關于緩存的詳細介紹以及緩存的面試問題可以參考這篇部落格

https://blog.csdn.net/zhengzhaoyang122/article/details/82184029

二、Spring緩存抽象

Spring從3.1開始定義了org.springframework.cache.Cache

和org.springframework.cache.CacheManager接口來統一不同的緩存技術;并支援使用JCache(JSR-107)注解簡化我們開發;

每次調用需要緩存功能的方法時,Spring會檢查檢查指定參數的指定的目标方法是否已經被調用過;如果有就直接從緩存中擷取方法調用後的結果,如果沒有就調用方法并緩存結果後傳回給使用者。下次調用直接從緩存中擷取。

使用Spring緩存抽象時我們需要關注以下兩點;

1、确定方法需要被緩存以及他們的緩存政策

2、從緩存中讀取之前緩存存儲的資料

springboot與緩存(整合redis)一、什麼是緩存二、Spring緩存抽象三、幾個重要概念&緩存注解四、springboot整合redis實作緩存五、@Cacheable注解六、@CachePut七、@CacheEvict八、@Caching

三、幾個重要概念&緩存注解

1、Cache:

緩存接口,定義緩存操作。實作有:RedisCache、EhCacheCache、ConcurrentMapCache等

2、CacheManager

緩存管理器,管理各種緩存(Cache)元件

3、@Cacheable

主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存

(後面會細說該注解)

4、@CacheEvict

清空緩存

5、@CachePut

保證方法被調用,又希望結果被緩存。

6、@EnableCaching

開啟基于注解的緩存

7、keyGenerator

緩存資料時key生成政策

8、serialize

緩存資料時value序列化政策

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

springboot與緩存(整合redis)一、什麼是緩存二、Spring緩存抽象三、幾個重要概念&緩存注解四、springboot整合redis實作緩存五、@Cacheable注解六、@CachePut七、@CacheEvict八、@Caching
springboot與緩存(整合redis)一、什麼是緩存二、Spring緩存抽象三、幾個重要概念&緩存注解四、springboot整合redis實作緩存五、@Cacheable注解六、@CachePut七、@CacheEvict八、@Caching

四、springboot整合redis實作緩存

1、引入依賴

在pom.xml中引入spring-boot-starter-data-redis依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>           

2、配置redis連接配接位址

在application.yml或者application.properties中配置redis連接配接位址

這裡還需要配置一下資料庫的位址,友善測試使用

application.properties配置

spring.datasource.url=jdbc:mysql://MySQL的主機位址:3306/資料庫名
spring.datasource.username=root
spring.datasource.password=密碼
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

# 啟用mybatis的命名政策(即駝峰命名法)
mybatis.configuration.map-underscore-to-camel-case=true

logging.level.com.atguigu.cache.mapper=debug

debug=true

spring.redis.host=redis主機位址
           

application.yml配置:

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://MySQL的主機位址:3306/資料庫名
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource #配置Druid資料源

    #   資料源其他配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    #   配置監控統計攔截的filters,去掉後監控界面sql無法統計,'wall'用于防火牆
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
  redis:
    host: redis主機位址
#mybatis:
#  config-location: classpath:mybatis/mybatis-config.xml
# 開啟駝峰命名
mybatis:
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    com.canghe.springboot.mapper: debug
debug: true
#  mapper-locations: classpath:mybatis/mapper/*.xml           

3、在虛拟機或者雲伺服器上安裝redis

可以直接通過docker安裝redis,并配置端口

4、使用RestTemplate操作redis

@Autowired
    StringRedisTemplate stringRedisTemplate;//操作k-v都是字元串

    @Autowired
    RedisTemplate redisTemplate;//操作k-v對象的           

Redis常見的五大資料類型

String(字元串) 、list(清單)、set(集合)、hash(散列)、Zset(有序集合)

  1. redisTemplate.opsForValue();//操作字元串
  2. redisTemplate.opsForHash();//操作hash
  3. redisTemplate.opsForList();//操作list
  4. redisTemplate.opsForSet();//操作set
  5. redisTemplate.opsForZSet();//操作有序set

測試代碼:

@Test
    public void test01() {
//        stringRedisTemplate.opsForValue().append("key","helloword");
//        String msg = stringRedisTemplate.opsForValue().get("key");
//        System.out.println("msg:"+msg);
        stringRedisTemplate.opsForList().leftPush("firstList","1");
        stringRedisTemplate.opsForList().leftPush("firstList","2");
    }           

五、@Cacheable注解

1、運作流程

1、方法運作之前,先去查詢Cache(緩存元件),按照cacheNames指定的名字擷取;(CacheManager先擷取相應的緩存),第一次擷取緩存如果沒有Cache元件會自動建立。

2、去Cache中查找緩存的内容,使用一個key,預設就是方法的參數; key是按照某種政策生成的;預設是使用keyGenerator生成的,預設使用SimpleKeyGenerator生成key; SimpleKeyGenerator生成key的預設政策;

如果沒有參數;key=new SimpleKey();
         如果有一個參數:key=參數的值
         如果有多個參數:key=new SimpleKey(params);
           

3、沒有查到緩存就調用目标方法;

4、将目标方法傳回的結果,放進緩存中

@Cacheable标注的方法執行之前先來檢查緩存中有沒有這個資料,預設按照參數的值作為key去查詢緩存,**

如果沒有就運作方法并将結果放入緩存;以後再來調用就可以直接使用緩存中的資料;**

2、核心

1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】元件

2)、key使用keyGenerator生成的,預設是SimpleKeyGenerator

3、幾個屬性

  • cacheNames/value:指定緩存元件的名字;将方法的傳回結果放在哪個緩存中,是數組的方式,可以指定多個緩存;
  • key:緩存資料使用的key;可以用它來指定。預設是使用方法參數的值 1-方法的傳回值, 編寫SpEL; #i d;參數id的值 #a0 #p0 #root.args[0] getEmp[2]
  • keyGenerator:key的生成器;可以自己指定key的生成器的元件id,key/keyGenerator:二選一使用;
  • cacheManager:指定緩存管理器;或者cacheResolver指定擷取解析器
  • condition:指定符合條件的情況下才緩存; condition = "#a0>1":第一個參數的值》1的時候才進行緩存
  • unless:否定緩存;當unless指定的條件為true,方法的傳回值就不會被緩存;可以擷取到結果進行判斷
    unless = "#result == null"
         *              unless = "#a0==2":如果第一個參數的值是2,結果不緩存;           
  • sync:是否使用異步模式

@Cacheable例子:

@Cacheable(value = {"emp"}/*,keyGenerator = "myKeyGenerator",condition = "#a0>1",unless = "#a0==2"*/)
    public Employee getEmp(Integer id){
        System.out.println("查詢"+id+"号員工");
        Employee emp = employeeMapper.getEmpById(id);
        return emp;
    }           

六、@CachePut

1、啟用場景

既調用方法,又更新緩存資料;同步更新緩存,修改了資料庫的某個資料,同時更新緩存;

2、運作時機

  • 先調用目标方法
  • 将目标方法的結果緩存起來

3、測試步驟

1、查詢1号員工;查到的結果會放在緩存中;

key:1  value:lastName:張三           

2、以後查詢還是之前的結果

3、更新1号員工;【lastName:zhangsan;gender:0】

将方法的傳回值也放進緩存了;
 key:傳入的employee對象  值:傳回的employee對象;           

4、查詢1号員工?

應該是更新後的員工;
 key = "#employee.id":使用傳入的參數的員工id;
 key = "#result.id":使用傳回後的id
  @Cacheable的key是不能用#result
  為什麼是沒更新前的?【1号員工沒有在緩存中更新】
           
@CachePut(/*value = "emp",*/key = "#result.id")
    public Employee updateEmp(Employee employee){
        System.out.println("updateEmp:"+employee);
        employeeMapper.updateEmp(employee);
        return employee;
    }           

七、@CacheEvict

緩存清除

/**
     * @CacheEvict:緩存清除
     *  key:指定要清除的資料
     *  allEntries = true:指定清除這個緩存中所有的資料
     *  beforeInvocation = false:緩存的清除是否在方法之前執行
     *      預設代表緩存清除操作是在方法執行之後執行;如果出現異常緩存就不會清除
     *
     *  beforeInvocation = true:
     *      代表清除緩存操作是在方法運作之前執行,無論方法是否出現異常,緩存都清除
     *
     *
     */
    @CacheEvict(value="emp",beforeInvocation = true/*key = "#id",*/)
    public void deleteEmp(Integer id){
        System.out.println("deleteEmp:"+id);
        //employeeMapper.deleteEmpById(id);
        int i = 10/0;
    }           

八、@Caching

定義複雜的緩存規則

@Caching(
         cacheable = {
             @Cacheable(/*value="emp",*/key = "#lastName")
         },
         put = {
             @CachePut(/*value="emp",*/key = "#result.id"),
             @CachePut(/*value="emp",*/key = "#result.email")
         }
    )           

The more effort,the more lucky

https://github.com/freestylefly/javaStudy https://github.com/freestylefly/javaStudy https://github.com/freestylefly/javaStudy

GitHub項目

https://github.com/freestylefly/javaStudy

https://github.com/freestylefly/javaStudy

springboot與緩存(整合redis)一、什麼是緩存二、Spring緩存抽象三、幾個重要概念&amp;緩存注解四、springboot整合redis實作緩存五、@Cacheable注解六、@CachePut七、@CacheEvict八、@Caching
springboot與緩存(整合redis)一、什麼是緩存二、Spring緩存抽象三、幾個重要概念&amp;緩存注解四、springboot整合redis實作緩存五、@Cacheable注解六、@CachePut七、@CacheEvict八、@Caching