Redis簡介
Redis使大規模互聯網應用常用的內存高速緩存數據庫,它的讀寫速度非常快。Redis是目前使用最廣泛的內存數據存儲系統之一。它支持更豐富的數據結構,支持數據持久化、事務、HA(高可用High Available)、雙機集羣系統、主從庫。
Redis是key-value存儲系統。它支持的value類型包括String、List、Set、Zset(有序集合)和Hash。這些數據類型都支持push/pop、add/remove,以及取交集、並集、差集或更豐富的操作,而且這些操作都是原子性的。在此基礎上,Redis支持各種不同方式的排序和算法。
Redis會週期性地把更新後的數據寫入磁盤,後把修改操作寫入追加的記錄文件中(RDB和AOF兩種方式),並且在此基礎上實現了master-slave同步。機器重啓後,能通過持久化數據自動重建內存。如果使用Redis作爲Cache,則機器宕機後熱點數據不會丟失。
Redis爲什麼快?
純內存操作;單線程操作,避免了頻繁的上下文切換;採用了非阻塞I/O多路複用機制。
1.Redis的使用場景
高併發的讀寫:Redis特別適合將方法的運行結果放入緩存,以便後續在請求方法時直接去緩存中讀取。對執行耗時,且結果不頻繁變動的SQL查詢的支持極好。在高併發的情況下,應儘量避免請求直接訪問數據庫,這時可以使用Redis進行緩衝操作,讓請求先訪問Redis。
計數器:電商網站商品的瀏覽量、視頻網站上視頻的播放數量等數據都會被統計,以便用於運營或產品分析。爲了保證數據實時生效,每次瀏覽量都得+1,這會導致非常高的併發量。這時可以用Redis提供的incr命令來實現計數器功能,這一切在內存中操作,所以性能非常好,非常適用於這些計數場景。
排行榜:可以利用Redis提供的有序集合數據類,實現各種複雜的排行榜應用。如京東、淘寶的銷售榜單,商品按時間、銷量排行。
分佈式會話:在集羣模式下,一般都會搭建以Redies等內存數據庫爲中心的Session服務,它不再有容器管理,而是由Session服務以及內存數據庫管理。
互動場景:使用Redis提供的散列、集合等數據結構,可以很方便地實現網站中點贊、踩、關注共同好友等社交場景的基本功能。
最新列表:Redis可以通過LPUSH在列表頭部插入一個內容ID作爲關鍵字,LTRIM可用來限制列表的數量,這樣列表永遠爲N個ID,無需查詢最新的列表,直接根據ID查找對應的內容即可。
2. Redis的數據類型
Redis有5種數據類型
數據類型 | 存儲的值 | 讀寫能力 |
---|---|---|
string(字符串) | 可以時字符串、正數或者浮點數 | 對整個字符串或字符串的一部分執行操作;對對象和浮點數執行自增或自減操作 |
list(列表) | 一個鏈表,鏈表上的每個節點都包含了一個字符串 | 從鏈表的兩端推入或彈出元素;根據偏移量對鏈表進行修剪(prim);讀取單個或多個元素;根據值來查找或移除元素 |
set(集合) | 包含字符串的無序收集器,並且每個字符串各不相同 | 添加、獲取、移除單個元素;檢查一個元素是否存在於某個集合中;計算交集、並集、差集;從集合裏隨機獲取元素 |
hash(散列) | 包含鍵值對的無序散列表 | 添加、獲取、移除單個鍵值對;獲取所有鍵值對 |
zset(有序集合) | 字符串成員與浮點數分值之間的有序映射,元素的排列順序由分值的大小決定 | 加、獲取、刪除單個元素;根據分值範圍或成員來獲取元素 |
1.字符串
Redis字符串可以包含任意類型的數據、字符、整數、浮點數等。一個字符串類型的值的容量時512MB,代表能存儲最大512MB的內容。可以使用INCR(DECR,INCRBY)命令來把字符串當作原子計數器使用。使用APPEND命令在字符串後面添加內容。應用場景:計數器。
2 列表
Redis列表是簡單的字符串列表,按照插入順序排序。可以通過LPUSH,RPUSH命令添加一個元素到列表的頭部或尾部。一個列表最多包含(約爲42.95億)個元素。應用場景:取最新N個數據的操作,消息隊列,刪除與過濾,實時分析正在發生的情況,數據統計與防止垃圾郵件。
3 集合
Redis集合是一個無序的、不允許相同成員存在的字符串集合。支持一些服務器端的命令從現有的集合出發去進行集合運算,如合併,求交集、差集,找出不同元素的操作。應用場景:Unique操作,可以獲取某段時間內所有數據的去重值,比如用於共同好友、二度好友、統計獨立IP、好友推薦等。
4 散列
Redis hash是字符串字段和字符串值之間的映射,主要用來表示對象,也能夠存儲許多元素。應用場景:存儲、讀取、修改用戶屬性。
5 有序集合
Redis有序集合不包含相同字符串,每個有序集合的 成員都關聯着一個評分,這個評分用於把有序集合中的成員按最低分到最高分排列。使用有序集合,可以非常快捷地完成添加、刪除、更新元素的操作。元素是在插入時就排好序,所以很快地通過評分(Score)或位次(Position)獲得一個範圍的元素。應用場景:排行榜應用、取TOP N操作,需要精準設定過期時間的應用(時間戳作爲Score)、帶有權重的元素(遊戲用戶得分排行榜)、過期項目處理、按照時間排序等。
3.用Redis Template操作Redis的5種數據類型
Spring封裝了Redis Template來操作Redis,它支持所有的Redis原生的API。在RedisTemplate中定義了對5種數據結構的操作方法。
- opsForValue():操作字符串
- opsForHash():操作散列
- opsForList():操作列表
- opsForSet():操作集合
- opsForZSet():操作有序集合
1)操作字符串
RedisTemplate提供以下操作String 的方法。
1.set void set(K key,V value);get V get(Object key);
具體使用見下面代碼
@Autowired
private RedisTemplate redisTemplate;
@Test
public void string(){
redisTemplate.opsForValue().set("num",123);
redisTemplate.opsForValue().set("nihao","I am lsz");
redisTemplate.opsForValue().set("lishizheng","first time using Redis");
Object s=redisTemplate.opsForValue().get("num");
Object s2=redisTemplate.opsForValue().get("nihao");
Object s3=redisTemplate.opsForValue().get("lishizheng");
System.out.println(s);
System.out.println(s2);
System.out.println(s3);
}
運行結果
123
I am lsz
first time using Redis
第一次使用Spring Boot使用redis,報錯如下
Unable to connect to 127.0.0.1:6379
原因是:自己沒有安裝Redis也沒有啓動Redis服務,自然無法連接。安裝並啓動Redis之後,可以正常連接Redis。另外這個界面需要一直打開以表示redis服務是開啓的,可能是還沒有配置的原因
2.set void set(K key,V value,long timeout,TimeUnit unit)
TimeUnit是java.util.concurrrent
包下面的一個類,表示給定單元粒度的時間段,常用的顆粒度有
- 天:TimeUnit.DAYS
- 小時:TimeUnit.HOURS
- 分鐘:TimeUnit.MINUTES
- 秒:TimeUnit.SECONDS
- 毫秒:TimeUnit.MILLISECONS
以下代碼設置3s失效。3s之內查詢有結果,如果3s之後查詢則會返回null。
@Test
public void string2(){
//設置的是3s失效
redisTemplate.opsForValue().set("num","dsafadfadaafaa",3, TimeUnit.SECONDS);
try {
Object s=redisTemplate.opsForValue().get("num");
System.out.println(s);
Thread.currentThread().sleep(2000);
Object s2=redisTemplate.opsForValue().get("num");
System.out.println(s2);
Thread.currentThread().sleep(5000);
Object s3=redisTemplate.opsForValue().get("num");
System.out.println(s3);
}catch (InterruptedException ie){
ie.printStackTrace();
}
}
控制檯輸出結果
dsafadfadaafaa
dsafadfadaafaa
null
3.set void set(K key,V value,long offset)
給定key所存儲的字符串值,從偏移量offset開始。具體用法見以下代碼
這裏遇到問題,報錯如下
Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.StreamCorruptedException: invalid stream header: 00000000
錯誤提示:序列號對象生成這個字節數組的方法是否與默認的反序列化方法相對應。
錯誤代碼
@Test
@Test
public void string3(){
//重寫給定key所存儲的字符串,從偏移量offset開始
redisTemplate.opsForValue().set("key","hello world");
System.out.println(redisTemplate.opsForValue().get("key"));
redisTemplate.opsForValue().set("key","git",6);
System.out.println(redisTemplate.opsForValue().get("key"));
}
原因分析:因爲本文的測試只是在test文件夾下寫的,main文件夾下面沒有東西,看來需要重新開始。這次重新開了一個Spring Boot項目,項目結構如下,在完成了這篇文章之後:SpringBoot使用Redis和MyBatis完成緩存數據的增刪改查,順手在test文件夾下新建controller,添加RedisTypeTest.java用來測試
這次注意了Redis序列化/發序列化的配置
配置Redis類
要想啓動Spring緩存支持,需要創建一個CacheManager的Bean。
RedisConfig.java
package com.example.demo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
@Configuration
public class RedisConfig extends CachingConfigurerSupport{
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
@SuppressWarnings("rawtypes")
@Bean
//緩存管理器
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheManager cacheManager = RedisCacheManager.create(connectionFactory);
//設置緩存過期時間
return cacheManager;
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
//配置連接工廠
StringRedisTemplate template = new StringRedisTemplate(factory);
//使用Jackson2JsonRedisSerializer來序列化和反序列化redis 的value值
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
//指定要序列化的域,field,get和set,以及修飾符範圍
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//指定序列化輸入的類型,類必須是非final類
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,
ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(om);
//序列化配置爲String格式
template.setValueSerializer(new StringRedisSerializer());
//
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
}
關於Redis Template中序列化和反序列化配置的解釋
關於數據的“序列化/反序列化”,提供了多種可選擇策略(RedisSerializer)
序列化/發序列化 | 解釋 |
---|---|
JdkSerializationRedisSerializer | POJO對象的存取場景,使用JDK本身序列化機制,將pojo類通過ObjectInputStream/ObjectOutputStream進行序列化操作,最終redis-server中將存儲字節序列。 |
StringRedisSerializer | 適用於Key或者value爲字符串的場景,根據指定的charset對數據的字節序列編碼成string |
JacksonJsonRedisSerializer | 提供了javabean與json之間的轉換能力,可以將pojo實例序列化成json格式存儲在redis中,也可以將json格式的數據轉換成pojo實例。 |
OxmSerializer | 提供了將javabean與xml之間的轉換能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存儲的數據將是xml工具。 |
上面4種策略中:
JdkSerializationRedisSerializer
和StringRedisSerializer
是最基礎的策略,在設計時仍然不推薦直接使用後面兩種,即JacksonJsonRedisSerializer
和OxmSerializer
,因爲無論是json還是xml,他們本身仍然是String。
如果數據需要被第三方工具解析,那麼數據應該使用StringRedisSerializer
而不是JdkSerializationRedisSerializer
。
如果數據格式必須爲json或者xml,那麼在編程級別,在redisTemplate配置中仍然使用StringRedisSerializer
,在存儲之前或者讀取之後,使用“SerializationUtils”工具轉換轉換成json或者xml
經過一番折騰
@Test
public void string3(){
//重寫給定key所存儲的字符串,從偏移量offset開始
redisTemplate.opsForValue().set("key","hello world");
System.out.println(redisTemplate.opsForValue().get("key"));
redisTemplate.opsForValue().set("key","git",6);
System.out.println(redisTemplate.opsForValue().get("key"));
}
結果爲
hello world
hello gitld
可以看到,從偏移量6開始用git字符串覆蓋掉原字符串。
4.getAndSet V getAndSet(K key,V value)
設置鍵的字符串值,並返回其舊值。具體用法如下:
@Test
public void string4(){
//設置鍵的字符串值並返回其舊值
redisTemplate.opsForValue().set("english","C primer plus");
System.out.println(redisTemplate.opsForValue().getAndSet("english","usage"));
System.out.println(redisTemplate.opsForValue().get("english"));
}
返回結果
C primer plus
usage
5.append Integer append(K key,String value)
如果key已經存在,已經是一個字符串,則該命令將該值追加到字符串的末尾。如果key不存在,則它將被創建並被設置爲空字符串。
@Test
public void string5() {
redisTemplate.opsForValue().set("k", "test");
redisTemplate.opsForValue().append("k","test");
System.out.println(redisTemplate.opsForValue().get("k"));
redisTemplate.opsForValue().append("k","forwhat");
System.out.println(redisTemplate.opsForValue().get("k"));
}
測試結果
testtest
testtestforwhat
這裏曾經遇到過問題Redis Template使用append方法不起作用的解決辦法以及序列化/反序列化的解釋
6.size Long size(K key)
返回key所對應的value值的長度
使用如下:下面將返回字符串howareu的長度,爲7
@Test
public void string6() {
redisTemplate.opsForValue().set("key","howareu");
System.out.println(redisTemplate.opsForValue().size("key"));
}
測試結果
7
2)操作散列
Redis hash是一個string類型的field和value的映射表,hash特別適合用於存儲對象。value中存放的是結構化的對象。利用這種數據結構,可以方便地操作其中的某個字段。比如在“點擊登錄”時,可以用這種數據結構存儲用戶信息。以CookedId作爲key,設置30分鐘爲緩存過期時間,能很好地模擬出類似Session的效果。
1.void putAll(H key,Map<? extends HK,? extends HV> m)
用m中提供的多個散列字段設置到key對應的散列表中。
舉例如下:這裏的m是testMap,這裏key 是Hash,可以看到結果,而key是hash,由於沒有設置因此爲空。
@Test
public void hash1(){
Map<String,Object> testMap=new HashMap();
testMap.put("name","shizheng");
testMap.put("sex","male");
redisTemplate.opsForHash().putAll("Hash",testMap);
System.out.println(redisTemplate.opsForHash().entries("Hash"));
System.out.println(redisTemplate.opsForHash().entries("hash"));
}
測試結果
{sex=male, name=shizheng}
{}
2.void put(H key,HK hashKey,HV value)
設置hashKey的值
@Test
public void hash2() {
redisTemplate.opsForHash().put("testName", "name", "shizheng");
redisTemplate.opsForHash().put("testName", "age", "100");
System.out.println(redisTemplate.opsForHash().entries("testName"));
System.out.println(redisTemplate.opsForHash().values("testName"));
}
測試結果
{name=shizheng, age=100}
[shizheng, 100]
3.List< HV> values(H key)
根據密鑰獲取整個散列存儲的值,用法如上
4.Map< HK,HV> entries(H key)
根據密鑰獲取整個散列存儲,用法如上
5.Long delete(H key,Object… hashKeys)
刪除給定的hashKeys
@Test
public void hash3() {
redisTemplate.opsForHash().put("testName", "name", "shizheng");
redisTemplate.opsForHash().put("testName", "age", "100");
System.out.println(redisTemplate.opsForHash().delete("testName","name"));
System.out.println(redisTemplate.opsForHash().entries("testName"));
}
測試結果
1
{age=100}
6.Boolean hashKey(H key,Object hashKey)
確定hashKey是否存在
@Test
public void hash4() {
redisTemplate.opsForHash().put("testName", "name", "shizheng");
redisTemplate.opsForHash().put("testName", "age", "100");
System.out.println(redisTemplate.opsForHash().hasKey("testName","name"));
System.out.println(redisTemplate.opsForHash().hasKey("testName","height"));
}
測試結果
true
false
7.HV get(H key,Object hashKey)
從散列獲取給定hashKey的值
具體用法:獲取name的值
@Test
//從鍵中的哈希獲取給定hashKey的值
public void hash7() {
redisTemplate.opsForHash().put("testName", "name", "shizheng");
redisTemplate.opsForHash().put("testName", "sex", "male");
System.out.println(redisTemplate.opsForHash().get("testName", "name"));
}
測試結果
shizheng
8.Set< HK> keys(H key)
獲取key所對應的key的值
@Test
//獲取key所對應的散列表的key
public void hash8() {
redisTemplate.opsForHash().put("testName", "name", "shizheng");
redisTemplate.opsForHash().put("testName", "sex", "male");
System.out.println(redisTemplate.opsForHash().keys("testName"));
}
測試結果
[name, sex]
9.Long size(H key)
獲取key所對應的散列表的大小個數
@Test
//獲取key所對應的散列表的大小個數
public void hash9() {
redisTemplate.opsForHash().put("testName", "name", "shizheng");
redisTemplate.opsForHash().put("testName", "sex", "male");
System.out.println(redisTemplate.opsForHash().size("testName"));
}
測試結果
2
3)操作列表
1.Long leftPushAll(K key,V… values)
含義:leftPushAll表示把一個數組插入列表中
@Test
//批量把一個數組插入到列表中
public void list1() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().leftPushAll("list", strings);
System.out.println(redisTemplate.opsForList().range("list", 0, -1));
}
輸出結果
[3, 2, 1]
2.Long size(K key)
含義:返回存儲在鍵中的列表的長度。如果鍵不存在,則將其解釋爲空列表,並返回0。當key存儲的值不是列表時返回錯誤。
@Test
//返回存儲在鍵中的列表的長度。如果鍵不存在,則將其解釋爲空列表,並返回0。當key存儲的值不是列表時返回錯誤。
public void list2() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().leftPushAll("list", strings);
System.out.println(redisTemplate.opsForList().size("list"));
}
測試結果
3
3 Long leftPush(K key,V value)
含義:將所有指定的值插入在鍵的列表的頭部。如果鍵不存在,則在執行推送操作之前將其創建爲空列表(從左邊插入)。
@Test
//將所有指定的值插入存儲在鍵的列表的頭部。如果鍵不存在,則在執行推送操作之前將其創建爲空列表。(從左邊插入)
public void list3() {
redisTemplate.opsForList().leftPush("list", "1");
System.out.println(redisTemplate.opsForList().size("list"));
redisTemplate.opsForList().leftPush("list", "2");
System.out.println(redisTemplate.opsForList().size("list"));
redisTemplate.opsForList().leftPush("list", "3");
System.out.println(redisTemplate.opsForList().size("list"));
}
測試結果
1
2
3
4 Long rightPush(K key,V value)
含義:將所有指定的值插入存儲在鍵的列表的頭部。如果鍵不存在,則在執行推送操作之前將其創建爲空列表。(從右邊插入)
@Test
//將所有指定的值插入存儲在鍵的列表的頭部。如果鍵不存在,則在執行推送操作之前將其創建爲空列表。(從右邊插入)
public void list4() {
redisTemplate.opsForList().rightPush("listRight", "1");
System.out.println(redisTemplate.opsForList().size("listRight"));
redisTemplate.opsForList().rightPush("listRight", "2");
System.out.println(redisTemplate.opsForList().size("listRight"));
redisTemplate.opsForList().rightPush("listRight", "3");
System.out.println(redisTemplate.opsForList().size("listRight"));
}
測試結果
1
2
3
5 Long rightPushAll(K key,V…values)
含義:通過rightPushAll方法向最右邊批量添加元素
@Test
//
public void list5() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list", strings);
System.out.println(redisTemplate.opsForList().range("list", 0, -1));
}
測試結果
[1, 2, 3]
6 void set(K key,long index,V value)
含義:在列表中index的位置設置value
@Test
//在列表中index的位置設置value值
public void list6() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list6", strings);
System.out.println(redisTemplate.opsForList().range("list6", 0, -1));
redisTemplate.opsForList().set("list6", 1, "值");
System.out.println(redisTemplate.opsForList().range("list6", 0, -1));
}
測試結果
[1, 2, 3, 1, 2, 3]
[1, 值, 3, 1, 2, 3]
7 Long remove(K key,long court,Object value)
含義:從存儲在鍵中的列表,刪除給定”count“值的元素的第1個計數事件。其中,參數count的含義如下:
count=0:刪除等於value的所有元素
count>0:刪除等於從頭到尾移動的值的元素
count<0:刪除等於從尾到頭移動的值的元素
@Test
//刪除列表中存儲的列表中第一次出現的
public void list7() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list7", strings);
System.out.println(redisTemplate.opsForList().range("list7", 0, -1));
redisTemplate.opsForList().remove("list7", 1, "2");//將刪除列表中存儲的列表中第一次出現的“2”。
System.out.println(redisTemplate.opsForList().range("list7", 0, -1));
}
測試結果
[1, 2, 3]
[1, 3]
8 V index(K key,long index)
含義:根據下標獲取列表中的值(下標從0開始)
@Test
//根據下標獲取列表中的值,下標是從0開始的
public void list8() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list8", strings);
System.out.println(redisTemplate.opsForList().range("list8", 0, -1));
System.out.println(redisTemplate.opsForList().index("list8", 2));
}
測試結果
[1, 2, 3]
3
9 V leftPop(K key)
含義:彈出最左邊的元素,彈出之後該值在列表中將不復存在
@Test
//彈出最左邊的元素,彈出之後該值在列表中將不復存在
public void list9() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list9", strings);
System.out.println(redisTemplate.opsForList().range("list9", 0, -1));
System.out.println(redisTemplate.opsForList().leftPop("list9"));
System.out.println(redisTemplate.opsForList().range("list9", 0, -1));
}
測試結果
[1, 2, 3]
3
[1, 2]
10 V rightPop(K key)
含義:彈出最右邊的元素,彈出之後該值在列表中將不復存在
@Test
//彈出最右邊的元素,彈出之後該值在列表中將不復存在
public void list10() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list10", strings);
System.out.println(redisTemplate.opsForList().range("list10", 0, -1));
System.out.println(redisTemplate.opsForList().rightPop("list10"));
System.out.println(redisTemplate.opsForList().range("list10", 0, -1));
}
測試結果
[1, 2, 1, 2, 3]
3
[1, 2, 1, 2]
4) 操作集合
1 Long add(K key,V…values)
含義:在無序集合中添加元素,返回添加個數
@Test
//無序集合中添加元素,返回添加個數
public void Set1() {
String[] strs = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("Set1", strs));
//也可以直接在add裏面添加多個值
System.out.println(redisTemplate.opsForSet().add("Set1", "1", "2", "3"));
}
測試結果
2 Long remove(K key,Object… values)
含義:移除集合中一個或多個成員
@Test
//移除集合中一個或多個成員
public void Set2() {
String[] strs = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("Set2", strs));
System.out.println(redisTemplate.opsForSet().remove("set2", strs));
}
3.V pop(K key)
含義:移除並返回集合中的一個隨機元素
@Test
//移除並返回集合中的一個隨機元素
public void Set3() {
String[] strs = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("Set3", strs));
System.out.println(redisTemplate.opsForSet().pop("Set3"));
System.out.println(redisTemplate.opsForSet().members("Set3"));
}
4 Boolean move( K key,V value,K destKey)
含義:將member元素移動
@Test
//將 member 元素從進行移動
public void Set4() {
String[] strs = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("Set4", strs));
redisTemplate.opsForSet().move("Set4", "str2", "Set4to2");
System.out.println(redisTemplate.opsForSet().members("Set4"));
System.out.println(redisTemplate.opsForSet().members("Set4to2"));
}
5 Long size(K key)
含義:獲取無序集合的大小長度
@Test
//無序集合的大小長度
public void Set5() {
String[] strs = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("Set5", strs));
System.out.println(redisTemplate.opsForSet().size("Set5"));
}
6 Set members(K key)
含義:返回集合中的所有成員
@Test
//返回集合中的所有成員
public void Set6() {
String[] strs = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("Set6", strs));
System.out.println(redisTemplate.opsForSet().members("Set6"));
}
7 Cursor< V > scan(K key,ScanOptions options)
含義:遍歷set
@Test
//遍歷set
public void Set7() {
String[] strs = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("Set7", strs));
Cursor<Object> curosr = redisTemplate.opsForSet().scan("Set7", ScanOptions.NONE);
while (curosr.hasNext()) {
System.out.println(curosr.next());
}
}
5)操作有序集合
1Long add(K key,Set< TypedTuple< V>> tuples)
含義:新增一個有序集合
2 Boolean add(K key,V value,double score)
含義:新增一個有序集合,如果存在則返回false,如果不存在則返回true
3 Long remove(K key,Object… values)
含義:從有序集合中移除一個或多個元素
4 Long rank(K key, Object o)
含義:返回有序集中指定成員的排名,按分數值遞增排列
5 Set< V > range(K key,long start,long end)
含義:通過索引區間返回有序集合指定區間內的成員,按分數值遞增排列
6 Long court(K key,double min,double max)
含義:通過分數返回有序集合指定區間內的成員個數
7 Long size(K key)
含義:獲取有序集合的成員數
8 Double score(K key, Object o)
含義:獲取指定成員的score
9 Long removeRange(K key,long start,long end)
含義:移除指定索引位置的成員,有序集合成員按分數值遞增排列
10 Cursor < TypedTuple < V > > scan(K key,ScanOptions options)
含義:遍歷zset
@Test
//新增一個有序集合
public void Zset1() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 9.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 9.9);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
System.out.println(redisTemplate.opsForZSet().add("zset1", tuples));
System.out.println(redisTemplate.opsForZSet().range("zset1", 0, -1));
}
@Test
//新增一個有序集合,存在的話爲false,不存在的話爲true
public void Zset2() {
System.out.println(redisTemplate.opsForZSet().add("zset2", "zset-1", 1.0));
System.out.println(redisTemplate.opsForZSet().add("zset2", "zset-1", 1.0));
}
@Test
//從有序集合中移除一個或者多個元素
public void Zset3() {
System.out.println(redisTemplate.opsForZSet().add("zset3", "zset-1", 1.0));
System.out.println(redisTemplate.opsForZSet().add("zset3", "zset-2", 1.0));
System.out.println(redisTemplate.opsForZSet().range("zset3", 0, -1));
System.out.println(redisTemplate.opsForZSet().remove("zset3", "zset-2"));
System.out.println(redisTemplate.opsForZSet().range("zset3", 0, -1));
}
@Test
//返回有序集中指定成員的排名,其中有序集成員按分數值遞增(從小到大)順序排列
public void Zset4() {
System.out.println(redisTemplate.opsForZSet().add("zset4", "zset-1", 1.0));
System.out.println(redisTemplate.opsForZSet().add("zset4", "zset-2", 1.0));
System.out.println(redisTemplate.opsForZSet().range("zset4", 0, -1));
System.out.println(redisTemplate.opsForZSet().rank("zset4", "zset-1"));
}
@Test
//通過索引區間返回有序集合成指定區間內的成員,其中有序集成員按分數值遞增(從小到大)順序排列
public void Zset5() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 9.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 9.1);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
System.out.println(redisTemplate.opsForZSet().add("zset5", tuples));
System.out.println(redisTemplate.opsForZSet().range("zset5", 0, -1));
}
@Test
//通過分數返回有序集合指定區間內的成員個數
public void Zset6() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 3.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 4.1);
ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3", 5.7);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
tuples.add(objectTypedTuple3);
System.out.println(redisTemplate.opsForZSet().add("zset6", tuples));
System.out.println(redisTemplate.opsForZSet().rangeByScore("zset6", 0, 9));
System.out.println(redisTemplate.opsForZSet().count("zset6", 0, 5));
}
@Test
//獲取有序集合的成員數
public void Zset7() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 3.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 4.1);
ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3", 5.7);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
tuples.add(objectTypedTuple3);
System.out.println(redisTemplate.opsForZSet().add("zset7", tuples));
System.out.println(redisTemplate.opsForZSet().size("zset7"));
}
@Test
//獲取指定成員的score值
public void Zset8() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 3.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 4.1);
ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3", 5.7);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
tuples.add(objectTypedTuple3);
System.out.println(redisTemplate.opsForZSet().add("zset8", tuples));
System.out.println(redisTemplate.opsForZSet().score("zset8", "zset-3"));
}
@Test
//獲取指定成員的score值
public void Zset9() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 3.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 5.1);
ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3", 2.7);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
tuples.add(objectTypedTuple3);
System.out.println(redisTemplate.opsForZSet().add("zset9", tuples));
System.out.println(redisTemplate.opsForZSet().range("zset9", 0, -1));
System.out.println(redisTemplate.opsForZSet().removeRange("zset9", 1, 2));
System.out.println(redisTemplate.opsForZSet().range("zset9", 0, -1));
}
@Test
//遍歷zset
public void Zset10() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1", 3.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2", 5.1);
ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3", 2.7);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
tuples.add(objectTypedTuple3);
System.out.println(redisTemplate.opsForZSet().add("zset10", tuples));
Cursor<ZSetOperations.TypedTuple<Object>> cursor = redisTemplate.opsForZSet().scan("zset10", ScanOptions.NONE);
while (cursor.hasNext()) {
ZSetOperations.TypedTuple<Object> item = cursor.next();
System.out.println(item.getValue() + ":" + item.getScore());
}
}
@Test
//遍歷zset
public void Zsetdss() {
//有十個庫存
Integer count = 100;
//添加到redis list中
for (Integer i = 0; i < count; i++) {
redisTemplate.opsForList().leftPush("slist", 1);
}
System.out.println(redisTemplate.opsForList().range("slist", 0, -1));
}
@Test
//遍歷zset
public void s2() {
//判斷計數器
if (redisTemplate.opsForList().size("slist") > 0) {
long user_id = 1903;
redisTemplate.opsForList().leftPush("ulist", user_id);
}
System.out.println(redisTemplate.opsForList().range("slist", 0, -1));
System.out.println(redisTemplate.opsForList().range("ulist", 0, -1));
}