一、前提
已經存在一個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”) |
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”) |
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 |