1. 程式人生 > 實用技巧 >【轉】 springboot整合redis-sentinel支援Cache註解

【轉】 springboot整合redis-sentinel支援Cache註解

【轉】 springboot整合redis-sentinel支援Cache註解

一、前提

已經存在一個redis-sentinel叢集,兩個哨兵分別如下:

/home/redis-sentinel-cluster/sentinel-1.conf
port 26379

dir "/data"
sentinel monitor mymaster 172.16.1.11 16379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 5000
sentinel parallel-syncs mymaster 1
/home/redis-sentinel-cluster/sentinel-2.conf
port 26380

dir "/data"
sentinel monitor mymaster 172.16.1.11 16379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 5000
sentinel parallel-syncs mymaster 1

二、新建maven工程:redis-sentinel-demo 最終完整工程如下:

pom.xml如下:

<?xml version="1.0" encoding="UTF-8"
?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.redis.sentinel.demo</
groupId> <artifactId>redis-sentinel-demo</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.7</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--以下是spring整合redis的依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies> </project>

1、application.yml

server:
  port: 8083
  context-path: /

spring:
  redis:
    sentinel:
      master: mymaster
      nodes: 172.16.1.11:26379,172.16.1.11:26380
    pool:
      max-active: 8
      max-idle: 8
      max-wait: -1
      min-idle: 0
    database: 0

2、新建redis的工具類RedisUtil

package com.redis.sentinel.demo.util;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author Administrator
 * @date 2019/03/19
 */
public class RedisUtil {

    private RedisTemplate<String, Object> redisTemplate;
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
    //=============================common============================
    /**
     * 指定快取失效時間
     * @param key 鍵
     * @param time 時間(秒)
     * @return
     */
    public boolean expire(String key,long time){
        try {
            if(time>0){
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根據key 獲取過期時間
     * @param key 鍵 不能為null
     * @return 時間(秒) 返回0代表為永久有效
     */
    public long getExpire(String key){
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判斷key是否存在
     * @param key 鍵
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key){
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 刪除快取
     * @param key 可以傳一個值 或多個
     */
    @SuppressWarnings("unchecked")
    public void del(String... key){
        if(key!=null&&key.length>0){
            if(key.length==1){
                redisTemplate.delete(key[0]);
            }else{
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }

    //============================String=============================
    /**
     * 普通快取獲取
     * @param key 鍵
     * @return*/
    public Object get(String key){
        return key==null?null:redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通快取放入
     * @param key 鍵
     * @param value 值
     * @return true成功 false失敗
     */
    public boolean set(String key,Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    /**
     * 普通快取放入並設定時間
     * @param key 鍵
     * @param value 值
     * @param time 時間(秒) time要大於0 如果time小於等於0 將設定無限期
     * @return true成功 false 失敗
     */
    public boolean set(String key,Object value,long time){
        try {
            if(time>0){
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            }else{
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 遞增
     * @param key 鍵
     * @param delta 要增加幾(大於0)
     * @return
     */
    public long incr(String key, long delta){
        if(delta<0){
            throw new RuntimeException("遞增因子必須大於0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 遞減
     * @param key 鍵
     * @param delta 要減少幾(小於0)
     * @return
     */
    public long decr(String key, long delta){
        if(delta<0){
            throw new RuntimeException("遞減因子必須大於0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    //================================Hash=================================
    /**
     * HashGet
     * @param key 鍵 不能為null
     * @param item 項 不能為null
     * @return*/
    public Object hget(String key,String item){
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 獲取hashKey對應的所有值
     * @param key 鍵
     * @return 對應的多個值
     */
    public Map<Object,Object> hmget(String key){
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     * @param key 鍵
     * @param map 對應多個鍵值
     * @return true 成功 false 失敗
     */
    public boolean hmset(String key, Map<String,Object> map){
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * HashSet 並設定時間
     * @param key 鍵
     * @param map 對應多個鍵值
     * @param time 時間(秒)
     * @return true成功 false失敗
     */
    public boolean hmset(String key, Map<String,Object> map, long time){
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if(time>0){
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一張hash表中放入資料,如果不存在將建立
     * @param key 鍵
     * @param item 項
     * @param value 值
     * @return true 成功 false失敗
     */
    public boolean hset(String key,String item,Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一張hash表中放入資料,如果不存在將建立
     * @param key 鍵
     * @param item 項
     * @param value 值
     * @param time 時間(秒)  注意:如果已存在的hash表有時間,這裡將會替換原有的時間
     * @return true 成功 false失敗
     */
    public boolean hset(String key,String item,Object value,long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if(time>0){
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 刪除hash表中的值
     * @param key 鍵 不能為null
     * @param item 項 可以使多個 不能為null
     */
    public void hdel(String key, Object... item){
        redisTemplate.opsForHash().delete(key,item);
    }

    /**
     * 判斷hash表中是否有該項的值
     * @param key 鍵 不能為null
     * @param item 項 不能為null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item){
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash遞增 如果不存在,就會建立一個 並把新增後的值返回
     * @param key 鍵
     * @param item 項
     * @param by 要增加幾(大於0)
     * @return
     */
    public double hincr(String key, String item,double by){
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash遞減
     * @param key 鍵
     * @param item 項
     * @param by 要減少記(小於0)
     * @return
     */
    public double hdecr(String key, String item,double by){
        return redisTemplate.opsForHash().increment(key, item,-by);
    }

    //============================set=============================
    /**
     * 根據key獲取Set中的所有值
     * @param key 鍵
     * @return
     */
    public Set<Object> sGet(String key){
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根據value從一個set中查詢,是否存在
     * @param key 鍵
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key,Object value){
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將資料放入set快取
     * @param key 鍵
     * @param values 值 可以是多個
     * @return 成功個數
     */
    public long sSet(String key, Object...values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 將set資料放入快取
     * @param key 鍵
     * @param time 時間(秒)
     * @param values 值 可以是多個
     * @return 成功個數
     */
    public long sSetAndTime(String key,long time,Object...values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if(time>0) expire(key, time);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 獲取set快取的長度
     * @param key 鍵
     * @return
     */
    public long sGetSetSize(String key){
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 移除值為value的
     * @param key 鍵
     * @param values 值 可以是多個
     * @return 移除的個數
     */
    public long setRemove(String key, Object ...values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    //===============================list=================================

    /**
     * 獲取list快取的內容
     * @param key 鍵
     * @param start 開始
     * @param end 結束  0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end){
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 獲取list快取的長度
     * @param key 鍵
     * @return
     */
    public long lGetListSize(String key){
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 通過索引 獲取list中的值
     * @param key 鍵
     * @param index 索引  index>=0時, 0 表頭,1 第二個元素,依次類推;index<0時,-1,表尾,-2倒數第二個元素,依次類推
     * @return
     */
    public Object lGetIndex(String key,long index){
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 將list放入快取
     * @param key 鍵
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將list放入快取
     * @param key 鍵
     * @param value 值
     * @param time 時間(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將list放入快取
     * @param key 鍵
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將list放入快取
     * @param key 鍵
     * @param value 值
     * @param time 時間(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根據索引修改list中的某條資料
     * @param key 鍵
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index,Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 用於移除鍵中指定的元素。接受3個引數,分別是快取的鍵名,計數事件,要移除的值。計數事件可以傳入的有三個值,分別是-1、0、1。
     -1代表從儲存容器的最右邊開始,刪除一個與要移除的值匹配的資料;0代表刪除所有與傳入值匹配的資料;1代表從儲存容器的最左邊開始,刪除一個與要移除的值匹配的資料。
     * @param key 鍵
     * @param count
     * @param value 值
     * @return 移除的個數
     */
    public void lRemove(String key,long count,Object value) {
        try {
            redisTemplate.opsForList().remove(key, count, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3、新建RedisConfig(主要是設定例項化redisTemplate,並設定序列化,同時例項化RedisUtil)

package com.redis.sentinel.demo.config;

import com.redis.sentinel.demo.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;



/**
 * @author Administrator
 * @date 2019/03/19
 */
@Configuration
@EnableCaching  //開啟快取,還要繼承於CachingConfigurerSupport,主要是為了註解@Cacheable、@CacheEvict、@CachePut等的使用
public class RedisConfig extends CachingConfigurerSupport {
    /**
     * 注入 RedisConnectionFactory
     */
    @Autowired
    RedisConnectionFactory redisConnectionFactory;

    /**
     * 例項化 RedisTemplate 物件
     *
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> functionDomainRedisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        initDomainRedisTemplate(redisTemplate, redisConnectionFactory);
        return redisTemplate;
    }

    /**
     * 設定資料存入 redis 的序列化方式
     *
     * @param redisTemplate
     * @param factory
     */
    private void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        //只有設定jdk序列化,才能新類物件比如User進行儲存
        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setConnectionFactory(factory);
    }

    /**
     * 例項化RedisUtil
     * @param redisTemplate
     * @return
     */
    @Bean
    public RedisUtil redisUtil(RedisTemplate<String, Object> redisTemplate) {
        RedisUtil redisUtil = new RedisUtil();
        redisUtil.setRedisTemplate(redisTemplate);
        return redisUtil;
    }
}

4、建立RedisTestController

package com.redis.sentinel.demo.controller;

import com.redis.sentinel.demo.model.User;
import com.redis.sentinel.demo.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author Administrator
 * @date 2019/03/19
 */
@RestController
@RequestMapping("/redis-sentinel")
public class RedisTestController {
    @Autowired
    private RedisUtil redisUtil;
    @RequestMapping(value = "/test",method = RequestMethod.POST)
    public void postTest(){
        testCommon();
        testHash();
        testSet();
        testList();
    }

    private void testCommon(){
        System.out.println("================================測試普通快取==================");
        System.out.println("普通快取,存入 key01 值為value01 到期時間為5秒");
        redisUtil.set("key01","value01",5);
        System.out.println("從redis獲取key01的值:"+redisUtil.get("key01"));
        System.out.println("到期時間為:"+redisUtil.getExpire("key01"));
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("6秒後從redis獲取key01的值:"+redisUtil.get("key01"));
        System.out.println("key01是否存在:"+redisUtil.hasKey("key01"));
    }

    private void testHash(){
        System.out.println("================================測試Hash快取==================");
        System.out.println("hash快取,存入 key03 值為{\"name\":\"zhangsan\",\"sex\":\"man\"}");
        Map<String,Object> map = new HashMap<>();
        map.put("name","zhangsan");
        map.put("sex","man");
        redisUtil.hmset("key03",map);
        System.out.println("key03:"+redisUtil.hget("key03","name")+"  "+redisUtil.hget("key03","sex"));
        redisUtil.del("key03");
    }

    private void testSet(){
        System.out.println("================================測試Set快取==================");
        System.out.println("Set快取,將兩個User放入快取key04");
        redisUtil.sSet("key04",new User("name1","man"),new User("name2","femal"));
        Set<Object> users = redisUtil.sGet("key04");
        for(Object o:users){
            User user = (User)o;
            System.out.println(o.toString());
        }
        System.out.println("獲取Set key04的長度:"+redisUtil.sGetSetSize("key04"));
        System.out.println("刪除key04");
        redisUtil.del("key04");
        System.out.println("獲取Set key04的長度:"+redisUtil.sGetSetSize("key04"));

    }

    private void testList(){
        System.out.println("================================測試List快取==================");
        System.out.println("List快取key05");
        redisUtil.lSet("key05", Arrays.asList("aa","bb","cc","dd","ee","ff","gg"));
        System.out.println("List快取key06");
        redisUtil.lSet("key06","11");
        redisUtil.lSet("key06","22");
        redisUtil.lSet("key06","33");
        redisUtil.lSet("key06","44");
        redisUtil.lSet("key06","55");
        redisUtil.lSet("key06","66");
        redisUtil.lSet("key06","77");
        System.out.println("以上兩種方式的快取是有區別的,注意看下面的長度");
        System.out.println("輸出key05的長度:"+redisUtil.lGetListSize("key05"));
        List<Object> list = redisUtil.lGet("key05",0,redisUtil.lGetListSize("key05"));
        System.out.println("輸出key05的所有元素");
        for(Object str:list){
            System.out.println(str);
        }
        System.out.println("輸出key06的長度:"+redisUtil.lGetListSize("key06"));
        List<Object> list1 = redisUtil.lGet("key06",0,redisUtil.lGetListSize("key06"));
        System.out.println("輸出key06的所有元素");
        for(Object str:list1){
            System.out.println(str);
        }

        System.out.println("刪除key06的的55");
        redisUtil.lRemove("key06",1,"55");
        List<Object> list2 = redisUtil.lGet("key06",0,redisUtil.lGetListSize("key06"));
        System.out.println("輸出key06的長度:"+redisUtil.lGetListSize("key06"));
        System.out.println("輸出key06的所有元素");
        for(Object str:list2){
            System.out.println(str);
        }

        redisUtil.del("key06");
        redisUtil.del("key05");

    }
}

5、建立springboot啟動類

package com.redis.sentinel.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author Administrator
 * @date 2019/03/19
 */
@SpringBootApplication
public class Application {
    public static void main(String[] args){
        SpringApplication.run(Application.class, args);
    }
}

6、啟動程式並用postman進行測試

================================測試普通快取==================
普通快取,存入 key01 值為value01 到期時間為5秒
從redis獲取key01的值:value01
到期時間為:4
6秒後從redis獲取key01的值:null
key01是否存在:false
================================測試Hash快取==================
hash快取,存入 key03 值為{"name":"zhangsan","sex":"man"}
key03:zhangsan  man
================================測試Set快取==================
Set快取,將兩個User放入快取key04
User{name='name2', sex='femal'}
User{name='name1', sex='man'}
獲取Set key04的長度:2
刪除key04
獲取Set key04的長度:0
================================測試List快取==================
List快取key05
List快取key06
以上兩種方式的快取是有區別的,注意看下面的長度
輸出key05的長度:1
輸出key05的所有元素
[aa, bb, cc, dd, ee, ff, gg]
輸出key06的長度:7
輸出key06的所有元素
11
22
33
44
55
66
77
刪除key06的的55
輸出key06的長度:6
輸出key06的所有元素
11
22
33
44
66
77

三、使用Cache註解

1、@Cacheable

@Cacheable是用來宣告方法是可快取的。將結果儲存到快取中以便後續使用相同引數呼叫時不需執行實際的方法。直接從快取中取值。最簡單的格式需要制定快取名稱。主要用於查詢。

引數 解釋 示例
value 快取的名稱,必須指定至少一個
@Cacheable(value=”users”)
@Cacheable(value={”users1”,”users2”}
key 快取的 key,可以為空,如果指定要按照 SpEL 表示式編寫,如果不指定,則預設按照方法的所有引數進行組合
@Cacheable(value = "users", key = "#name")
@Cacheable(value = "users", key = "#p0")
condition 快取的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進行快取
@Cacheable(value = "users",key = "#p0", condition = "#p0 != null")

2、@CachePut

如果快取需要更新,且不干擾方法的執行,可以使用註解@CachePut。@CachePut標註的方法在執行前不會去檢查快取中是否存在之前執行過的結果,而是每次都會執行該方法,並將執行結果以鍵值對的形式存入指定的快取中。

引數 解釋 示例
value 快取的名稱,必須指定至少一個
@CachePut(value=”users”)
@CachePut(value={”users1”,”users2”}
key 快取的 key,可以為空,如果指定要按照 SpEL 表示式編寫,如果不指定,則預設按照方法的所有引數進行組合
@CachePut(value = "users", key = "#name")
@CachePut(value = "users", key = "#p0")
condition 快取的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進行快取
@CachePut(value = "users",key = "#p0", condition = "#p0 != null")

3、@CacheEvict

@CachEvict 的作用 主要針對方法配置,能夠根據一定的條件對快取進行清空

引數 解釋 示例
value 快取的名稱,必須指定至少一個
@CacheEvict(value=”users”)
key 快取的 key,可以為空,如果指定要按照 SpEL 表示式編寫,如果不指定,則預設按照方法的所有引數進行組合
@CacheEvict(value = "users", key = "#name")
@CacheEvict(value = "users", key = "#p0")
condition 快取的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進行快取
@CacheEvict(value = "users",key = "#p0", condition = "#p0 != null")
allEntries 預設為 false,如果指定為 true,則方法呼叫後將立即清空所有快取
@CacheEvict(value = "users",allEntries=true)
beforeInvocation 預設為 false,如果指定為 true,則在方法還沒有執行的時候就清空快取,預設情況下,如果方法執行丟擲異常,則不會清空快取
@CacheEvict(value = "users",beforeInvocation=true)

4、@Caching

有時候我們可能組合多個Cache註解使用

以上四個個註解的示例程式如下:

在上面的程中新建RedisCachableController

package com.redis.sentinel.demo.controller;

import com.redis.sentinel.demo.model.User;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Administrator
 * @date 2019/03/21
 */
@RestController
@RequestMapping("/redis-sentinel-cache")
public class RedisCachableController {

    private Map<String, Object> userList = new HashMap<>();
    /**
     * 按key為user.name進行快取
     * @param user
     * @return
     */
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @CachePut(value = "users", key = "#user.name")
    public User addUser(@RequestBody User user) {
        userList.put(user.getName(), user);
        return user;
    }

    /**
     * 組合多個Cache註解使用,按user.name和user.sex兩個維度進行快取
     * @param user
     * @return
     */
    @RequestMapping(value = "/add2", method = RequestMethod.POST)
    @Caching(put = {
            @CachePut(value = "users", key = "#user.name"),
            @CachePut(value = "users", key = "#user.sex")
    })
    public User addUser2(@RequestBody User user) {
        userList.put(user.getName(), user);
        return user;
    }


    /**
     * 先從快取查資料,如果快取沒有,則到userList裡面去拿。
     * @param name
     * @return
     */
    @RequestMapping(value = "/query", method = RequestMethod.GET)
    @Cacheable(value = "users", key = "#name", condition = "#name != null")
    public User queryUserByName(@RequestParam(value = "name") String name) {
        System.out.println("如果快取沒有,從map裡面獲取");
        User user = (User) userList.get(name);
        return user;
    }

    /**
     * 刪除資料,從快取中刪除
     * @param name
     */
    @RequestMapping(value = "/del", method = RequestMethod.PUT)
    @CacheEvict(value = "users", key = "#name", condition = "#name != null")
    public void deleteUserByName(@RequestParam(value = "name") String name) {

    }
}

啟動程式,用postman進行測試

1)執行add方法,將資訊存入快取

2)執行query方法,檢視console

3)執行del方法,刪除快取

4)執行query方法,檢視console

5、@CacheConfig

所有的@Cacheable()裡面都有一個value=“xxx”的屬性,這顯然如果方法多了,寫起來也是挺累的,如果可以一次性宣告完 那就省事了,所以,有了@CacheConfig這個配置,作用在類上面,可以將上面的Controller類進行改造

在上面的程中新建RedisCachableController1

package com.redis.sentinel.demo.controller;

import com.redis.sentinel.demo.model.User;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Administrator
 * @date 2019/03/21
 */
@RestController
@RequestMapping("/redis-sentinel-cache2")
@CacheConfig(cacheNames = "users")
public class RedisCachableController1 {

    private Map<String, Object> userList = new HashMap<>();
    /**
     * 按key為user.name進行快取
     * @param user
     * @return
     */
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @CachePut(key = "#user.name")
    public User addUser(@RequestBody User user) {
        userList.put(user.getName(), user);
        return user;
    }

    /**
     * 組合多個Cache註解使用,按user.name和user.sex兩個維度進行快取
     * @param user
     * @return
     */
    @RequestMapping(value = "/add2", method = RequestMethod.POST)
    @Caching(put = {
            @CachePut( key = "#user.name"),
            @CachePut( key = "#user.sex")
    })
    public User addUser2(@RequestBody User user) {
        userList.put(user.getName(), user);
        return user;
    }


    /**
     * 先從快取查資料,如果快取沒有,則到userList裡面去拿。
     * @param name
     * @return
     */
    @RequestMapping(value = "/query", method = RequestMethod.GET)
    @Cacheable( key = "#p0", condition = "#p0 != null")
    public User queryUserByName(@RequestParam(value = "name") String name) {
        System.out.println("如果快取沒有,從map裡面獲取");
        User user = (User) userList.get(name);
        return user;
    }

    /**
     * 刪除資料,從快取中刪除
     * @param name
     */
    @RequestMapping(value = "/del", method = RequestMethod.PUT)
    @CacheEvict(key = "#name", condition = "#name != null")
    public void deleteUserByName(@RequestParam(value = "name") String name) {

    }
}

SpEL表示式

Spring Cache提供了一些供我們使用的SpEL上下文資料,下表直接摘自Spring官方文件:

名稱位置描述示例
methodName root物件 當前被呼叫的方法名 root.methodName
method root物件 當前被呼叫的方法 root.method.name
target root物件 當前被呼叫的目標物件 root.target
targetClass root物件 當前被呼叫的目標物件類 root.targetClass
args root物件 當前被呼叫的方法的引數列表 root.args[0]
caches root物件 當前方法呼叫使用的快取列表(如@Cacheable(value={“cache1”, “cache2”})),則有兩個cache root.caches[0].name
argument name 執行上下文 當前被呼叫的方法的引數,如findById(Long id),我們可以通過#id拿到引數 user.id
result 執行上下文 方法執行後的返回值(僅當方法執行之後的判斷有效,如‘unless’,’cache evict’的beforeInvocation=false) result