redis(一)-數據類型

參考資料:
redis 4.x cookbook 中文版;
redis官方文檔
注: 本文redis的版本爲: 5.0.3

redis學習路徑

數據類型:

目前包括: 字符串類型-string; 列表-list; 散列-hash; 集合-set ;有序集合-sorted set ;HyperLogLog ;Geo;

因爲redis中存儲的數據都是二進制的
所以如果我們使用jedis這類工具與redis交互時,需要考慮編碼的問題;通常在插入redis前與獲取數據後統一使用同一種編碼;避免不同物理機上可能存在的編碼不同的問題;

  • 字符串類型-string

這是最基礎也是最簡單的數據類型;
在redis中,有三種編碼用於存儲string:
int存儲64位有符號整數;
embstr存儲低於44字節的字符串,在內存中使用,性能最高;
raw存儲大於44字節的字符串;
redis會根據存儲的數據來選擇;可以通過OBJECT ENCODING key查看對應value的編碼;

#設置值,key已存在,覆蓋舊值;
#SET key value [EX seconds] [PX milliseconds] [NX|XX]
#EX(爲key設置過期時間,單位秒),PX(爲key設置過期時間,單位毫秒);
#NX(不存在才設置值),XX(存在才設置值)
127.0.0.1:6379> set test testValue
OK
#獲取值
127.0.0.1:6379> get test
"testValue"
#當key不存在時設置;當key存在時不做任何處理;設置成功返回1;
#這個命令可以用作分佈式鎖(併發量不高的情況下),需要結合lua腳本,避免線程安全問題;後續再講;
127.0.0.1:6379> setnx test testValue1
(integer) 0
127.0.0.1:6379> setnx test1 testValue1
(integer) 1
#獲取不存在的key,返回nil
127.0.0.1:6379> get test2
(nil)
#獲取key對應的value的長度;不存在的key,返回0;
127.0.0.1:6379> strlen test
(integer) 9
127.0.0.1:6379> strlen test2
(integer) 0
#覆蓋對應key的值,從指定位置開始;從0開始,下標爲4的開始被替換,testValue->test123ue;返回替換後的長度;
127.0.0.1:6379> setrange test 4 123
(integer) 9
127.0.0.1:6379> get test
"test123ue"
#爲對應key的value追加字符串;返回追加後的長度;key不存在時,爲key設置一個空字符串,再執行append;
127.0.0.1:6379> append test 456
(integer) 12
127.0.0.1:6379> get test
"test123ue456"
#MSET/MGET,是設置與獲取的批量操作;MSET無法像SET一樣傳遞參數;
#同理,MSETNX是SETNX的批量操作;
127.0.0.1:6379> MSET test1 testValue_1 test2 testValue_2 test3 testValue_3
OK
127.0.0.1:6379> MGET test1 test2 test3
1) "testValue_1"
2) "testValue_2"
3) "testValue_3"
127.0.0.1:6379>

  • 列表-list

存儲一組對象,由於數據結構的原因,它可以用於實現隊列[先進先出],棧[先進後出];
redis中的list其實是個雙端鏈表,既可以從開始插入/彈出,也可以從末尾插入/彈出;

#左側依次插入數據,這裏傳入多個數據,按順序插入;在數據庫中應是:t3,t2,t1;返回list長度;
#lpushx/rpushx,當key不存在時,不做操作;
127.0.0.1:6379> lpush testList t1 t2 t3
(integer) 3
#查看長度;
127.0.0.1:6379> llen testList
(integer) 3
#從左側彈出一個值;前面知道t3在最左側,因此被彈出;被彈出後,list中將會把這個值移除,因此長度爲2;
127.0.0.1:6379> lpop testList
"t3"
127.0.0.1:6379> llen testList
(integer) 2
#右側依次插入數據,數據庫中結果應是:t2,t1,t4,t5,t6;返回list長度
127.0.0.1:6379> rpush testList t4 t5 t6
(integer) 5
#右側彈出值,t6;列表中將其移除;
127.0.0.1:6379> rpop testList
"t6"
127.0.0.1:6379> llen testList
(integer) 4
#從設定的下標開始,到指定的下標結束,獲取所有值(注意,這裏獲取時,包括起始於結束下標位置的值)
#此方法獲取值,不會從list中移除對應值;
127.0.0.1:6379> lrange testList 1 2
1) "t1"
2) "t4"
127.0.0.1:6379> lrange testList 0 3
1) "t2"
2) "t1"
3) "t4"
4) "t5"
127.0.0.1:6379> llen testList
(integer) 4
#rpoplpush list1 list2;	將list1最右側的值彈出,作爲list2最左側的值;list1,list2可以是同一個key;
#返回被彈出和插入的值;
#list2不存在時,將會新建一個list2;
127.0.0.1:6379> rpoplpush testList testList
"t5"
127.0.0.1:6379> lrange testList 0 3
1) "t5"
2) "t2"
3) "t1"
4) "t4"
#lrem key count value,從key中移除count個等於value的值(精確匹配);返回被移除的value個數;
127.0.0.1:6379> lrem testList 5 t
(integer) 0
127.0.0.1:6379> lrange testList 0 3
1) "t5"
2) "t2"
3) "t1"
4) "t4"
127.0.0.1:6379> lrem testList 5 t5
(integer) 1
127.0.0.1:6379> lrange testList 0 3
1) "t2"
2) "t1"
3) "t4"
#根據下標返回對應值;不移除值;
127.0.0.1:6379> lindex testList 0
"t2"
#linsert key before/after targetValue value;
#將value插入到list中目標值的前面/後面;key不存在時不做操作,list中目標值不存在時也不做操作(返回-1);
#操作成功後返回list總長度;
127.0.0.1:6379> linsert testList before 1 t
(integer) -1
127.0.0.1:6379> lrange testList 0 3
1) "t2"
2) "t1"
3) "t4"
127.0.0.1:6379> linsert testList before t1 t
(integer) 4
127.0.0.1:6379> lrange testList 0 3
1) "t2"
2) "t"
3) "t1"
4) "t4"
#將對應下標的值設置爲新值;
127.0.0.1:6379> lset testList 1 tn
OK
127.0.0.1:6379> lrange testList 0 4
1) "t2"
2) "tn"
3) "t1"
4) "t4"
#將list從指定開始下標(含)到指定結束下標(含)之間的值保留,其他值都移除
127.0.0.1:6379> ltrim testList 1 2
OK
127.0.0.1:6379> llen testList
(integer) 2
127.0.0.1:6379> lrange testList 0 4
1) "tn"
2) "t1"
#BRPOPLPUSH list1 list2 timeout;rpoplpush list1 list2的阻塞版本;
#timeout設置爲0時意味着可以無限阻塞;單位是秒;
#假如在指定時間內沒有任何元素被彈出,則返回一個 nil 和等待時長;
127.0.0.1:6379> brpoplpush testList testList 0
"t1"
127.0.0.1:6379> lrange testList 0 4
1) "t1"
2) "tn"
127.0.0.1:6379> brpoplpush testList2 testList2 5
(nil)
(5.08s)
#阻塞的左側彈出操作,從傳入的多個key中,找到第一個list不爲空的key,彈出該list的最左側的值;
#返回被彈出值的key,被彈出的值;
#如果所有key都是空list,則阻塞到設定時間後,返回nil,等待時間;
#BRPOP同理;
127.0.0.1:6379> blpop testList2 testList testList1 3
1) "testList"
2) "t1"
127.0.0.1:6379> lrange testList 0 4
1) "tn"
127.0.0.1:6379> lrange testList1 0 4
1) "t1"
127.0.0.1:6379> blpop testList3 testList4 testList5 3
(nil)
(3.00s)

當多個客戶端對同一個key執行阻塞操作時,將會以隊列形式處理;先阻塞先執行;

  • 散列-hash

與hashtable類似,redis中的hash類型一樣是key-value存儲;也有rehash操作;

#設置值;
127.0.0.1:6379> hset testhash field1 value1
(integer) 1
127.0.0.1:6379> hset testhash field2 value2
(integer) 1
#獲取值;
127.0.0.1:6379> hget testhash field1
"value1"
#獲取所有key-value,大數據量慎用;
127.0.0.1:6379> hgetall testhash
1) "field1"
2) "value1"
3) "field2"
4) "value2"
#與setnx類似,不存在時設置值;
127.0.0.1:6379> hsetnx testhash field3 value3
(integer) 1
127.0.0.1:6379> hsetnx testhash field3 value3-1
(integer) 0
#hash中是否存在field
127.0.0.1:6379> hexists testhash field
(integer) 0
127.0.0.1:6379> hexists testhash field1
(integer) 1
#移除hash中的field
127.0.0.1:6379> hdel testhash field3
(integer) 1
127.0.0.1:6379> hexists testhash field3
(integer) 0
127.0.0.1:6379> hlen testhash
(integer) 2
#獲取對應field的value長度;
127.0.0.1:6379> hstrlen testhash field1
(integer) 6
127.0.0.1:6379> hget testhash field1
"value1"
#爲某個field的value進行整數運算;最後的參數可以是負數(相當於做減法);
#當value不爲數字時,會返回錯誤;運算成功過後,返回運算後的值;
127.0.0.1:6379> hincrby testhash field1 100
(error) ERR hash value is not an integer
127.0.0.1:6379> hset testhash field4 50
(integer) 1
127.0.0.1:6379> hincrby testhash field4 100
(integer) 150
127.0.0.1:6379> hget testhash field4
"150"
#爲某個field的value進行浮點數運算;最後的參數可以是負數(相當於做減法);
#當value不爲數字時,會返回錯誤;運算成功過後,返回運算後的值;
127.0.0.1:6379> hincrbyfloat testhash field1 1.02
(error) ERR hash value is not a float
127.0.0.1:6379> hincrbyfloat testhash field4 1.02
"151.02"
127.0.0.1:6379> hget testhash field4
"151.02"
#批量設置值;
127.0.0.1:6379> hmset testhash field5 value5 field6 value6 field7 value7
OK
#批量獲取hash下多個field的值;不存在的field返回nil;
127.0.0.1:6379> hmget testhash field1 field3
1) "value1"
2) (nil)
127.0.0.1:6379> hmget testhash field1 field4 field5
1) "value1"
2) "151.02"
3) "value5"
#獲取所有key;由於不支持模糊匹配,所以在生產環境中可以用;
127.0.0.1:6379> hkeys testhash
1) "field1"
2) "field2"
3) "field4"
4) "field5"
5) "field6"
6) "field7"
#獲取所有value;由於不支持模糊匹配,所以在生產環境中可以用;
127.0.0.1:6379> hvals testhash
1) "value1"
2) "value2"
3) "151.02"
4) "value5"
5) "value6"
6) "value7"
#hash的掃描;
#hscan key 開始遊標(客戶端進行第一次遍歷時,必須爲0) match 正則表達式 count 計數器(期望返回的個數);
#返回下一次遍歷開始的遊標,當返回0,意味着本次遍歷已經結束;
#請注意,最後的count值爲3,但是實際上卻返回了hash中所有的field;
#這是由於在redis中,當hash的鍵值對數量少於hash-max-ziplist-entries配置的值時,以ziplist數據類型存儲;
#ziplist數據類型是打包後的數據類型,因此不支持遍歷,所以返回所有符合條件的數據;
#當鍵值對大於設置值時,將會轉換成hashtable數據結構,使用count字段會起到效果;
#但是,redis不保證每次返回的數據都恰好等於count;
#hscan支持併發訪問,因爲每個客戶端訪問都會帶來一個遊標,同時返回一個新的遊標,互相之間不影響;
127.0.0.1:6379> hscan testhash 0 match field* count 3
1) "0"
2)  1) "field1"
    2) "value1"
    3) "field2"
    4) "value2"
    5) "field4"
    6) "151.02"
    7) "field5"
    8) "value5"
    9) "field6"
   10) "value6"
   11) "field7"
   12) "value7"

hash中比較複雜的就是hscan命令了;

  • 集合-set

唯一,無序的對象集合;
通常用來判斷對象是否存在,重複刪除,並集交集差集等運算;
set-max-intset-entries設置的值,以及集合中元素數據類型可以決定set以何種格式式存儲數據;
大於設置值或者集合不全是int,將以hashtable數據結構存儲;
小於設置值且集合全是int,以intset格式存儲;(此種格式存儲速度非常快);

#添加值到集合中,集合不存在則創建新集合;
127.0.0.1:6379> sadd testset value1 value2 value3
(integer) 3
#是否存在指定值;
127.0.0.1:6379> sismember testset value
(integer) 0
127.0.0.1:6379> sismember testset value1
(integer) 1
#移除集合中前面N個值;
127.0.0.1:6379> spop testset 1
1) "value1"
127.0.0.1:6379> sscan testset 0
1) "0"
2) 1) "value2"
   2) "value3"
#隨機從集合中獲得一個值;
127.0.0.1:6379> srandmember testset 1
1) "value2"
127.0.0.1:6379> srandmember testset 1
1) "value2"
127.0.0.1:6379> srandmember testset 1
1) "value2"
127.0.0.1:6379> srandmember testset 1
1) "value3"
#移除一個值;如不存在返回0;可批量移除,成功後返回移除的個數;
127.0.0.1:6379> srem testset value1
(integer) 0
127.0.0.1:6379> srem testset value2
(integer) 1
127.0.0.1:6379> sscan testset 0
1) "0"
2) 1) "value3"
#證明了set類型是無序集合;
127.0.0.1:6379> sadd testset value4 value5 value6
(integer) 3
127.0.0.1:6379> sscan testset 0
1) "0"
2) 1) "value5"
   2) "value3"
   3) "value6"
   4) "value4"
127.0.0.1:6379> smove testset testset1 value5
(integer) 1
#遍歷操作,與hash保持一致;
127.0.0.1:6379> sscan testset1 0
1) "0"
2) 1) "value5"
127.0.0.1:6379> sscan testset 0
1) "0"
2) 1) "value3"
   2) "value6"
   3) "value4"
#結果集大小(對象數量);
127.0.0.1:6379> scard testset
(integer) 3
127.0.0.1:6379> sinter testset testset1
(empty list or set)
#得到集合中所有數據;
127.0.0.1:6379> smembers testset
1) "value3"
2) "value6"
3) "value4"
127.0.0.1:6379> sadd testset value5
(integer) 1
#sinter 兩個集合的交集;
#sinterstore 新集合 集合1 集合2;sinter 的結果集寫入新集合(如存在則覆蓋);返回結果集大小;
127.0.0.1:6379> sinter testset testset1
1) "value5"
127.0.0.1:6379> sinterstore testset3  testset testset1
(integer) 1
127.0.0.1:6379> smembers testset3
1) "value5"
127.0.0.1:6379> sadd testset1 value_1 value_2 value_3 value_4 value_5
(integer) 5
#sunion 兩個集合的合集;
#sunionstore 新集合 集合1 集合2;將sunion 的結果集寫入新集合(如存在則覆蓋);返回結果集大小;
127.0.0.1:6379> sunion testset testset1
1) "value_4"
2) "value_1"
3) "value3"
4) "value_2"
5) "value6"
6) "value4"
7) "value_3"
8) "value5"
9) "value_5"
127.0.0.1:6379> smembers testset
1) "value5"
2) "value3"
3) "value6"
4) "value4"
127.0.0.1:6379> smembers testset1
1) "value_1"
2) "value_4"
3) "value_5"
4) "value_2"
5) "value_3"
6) "value5"
127.0.0.1:6379> smembers testset3
1) "value5"
#sdiff 集合1 集合2;
#以集合1爲準,返回的結果集是集合2中沒有的數據;如果集合1是集合2的子集,則返回空集合;
#sdiffstore 新集合 集合1 集合2;sdiff 的結果集寫入新集合(如存在則覆蓋);返回結果集大小;
127.0.0.1:6379> sdiff testset1 testset
1) "value_4"
2) "value_1"
3) "value_5"
4) "value_2"
5) "value_3"
127.0.0.1:6379> sdiff testset3 testset
(empty list or set)
  • 有序集合-sorted set

存儲的數據都是根據分數排序好的數據;
當某個值的分數被改變時,如果它與它後面的值具有同樣的分數,將會按照原來的順序排列;
分數可以爲負;

#插入值,nx|xx參數與set nx|xx保持一致;
#插入值是,必須是 分數 值 分數 值;且分數必須是數字(可以是浮點數);
127.0.0.1:6379> zadd testrank nx 10 1 20 2 30 3
(integer) 3
#獲取有序集合的大小;
127.0.0.1:6379> zcard testrank
(integer) 3
#遍歷;
127.0.0.1:6379> zscan testrank 0
1) "0"
2) 1) "1"
   2) "10"
   3) "2"
   4) "20"
   5) "3"
   6) "30"
#獲取某個值的權重(分數);
127.0.0.1:6379> zscore testrank 3
"30"
#修改分數;
127.0.0.1:6379> zincrby testrank 10 1
"20"
127.0.0.1:6379> zscan testrank 0
1) "0"
2) 1) "1"
   2) "20"
   3) "2"
   4) "20"
   5) "3"
   6) "30"
127.0.0.1:6379> zincrby testrank 10 1
"30"
127.0.0.1:6379> zscan testrank 0
1) "0"
2) 1) "2"
   2) "20"
   3) "1"
   4) "30"
   5) "3"
   6) "30"
#統計對應分數之間的值個數;
127.0.0.1:6379> zcount testrank 20 20
(integer) 1
127.0.0.1:6379> zincrby testrank 10 1
"40"
127.0.0.1:6379> zcount testrank 20 30
(integer) 2
127.0.0.1:6379> zcount testrank 20 40
(integer) 3
127.0.0.1:6379> zadd testrank -1 4
(integer) 1
127.0.0.1:6379> zscan testrank 0
1) "0"
2) 1) "4"
   2) "-1"
   3) "2"
   4) "20"
   5) "3"
   6) "30"
   7) "1"
   8) "40"
#正序獲取值;
127.0.0.1:6379> zrange testrank 0 1
1) "4"
2) "2"
#倒序獲取值;
127.0.0.1:6379> zrevrange testrank 0 1
1) "1"
2) "3"
#根據分數,正序獲取值;
127.0.0.1:6379> zrangebyscore testrank -1 10
1) "4"
127.0.0.1:6379> zrangebyscore testrank -1 20
1) "4"
2) "2"
#根據分數,倒序獲取值;
127.0.0.1:6379> zrevrangebyscore testrank -1 20
(empty list or set)
127.0.0.1:6379> zrevrangebyscore testrank 20 -1
1) "2"
2) "4"
#從集合的正序中,獲取某個值的下標;
127.0.0.1:6379> zrank testrank 4
(integer) 0
127.0.0.1:6379> zrank testrank 1
(integer) 3
127.0.0.1:6379> zrank testrank 20
(nil)
127.0.0.1:6379> zrank testrank 2
(integer) 1
127.0.0.1:6379> zscan testrank 0
1) "0"
2) 1) "4"
   2) "-1"
   3) "2"
   4) "20"
   5) "3"
   6) "30"
   7) "1"
   8) "40"
127.0.0.1:6379> zrank testrank 3
(integer) 2
#從集合的倒序中,獲取某個值的下標;
127.0.0.1:6379> zrevrank testrank 1
(integer) 0
#移除值,可以是多個;
127.0.0.1:6379> zrem testrank 1
(integer) 1
127.0.0.1:6379> zscan testrank 0
1) "0"
2) 1) "4"
   2) "-1"
   3) "2"
   4) "20"
   5) "3"
   6) "30"   
#根據值的順序,從有序集合中移除符合條件的值;
127.0.0.1:6379> zremrangebyrank testrank 0 0
(integer) 1
127.0.0.1:6379> zscan testrank 0
1) "0"
2) 1) "2"
   2) "20"
   3) "3"
   4) "30"
127.0.0.1:6379> zremrangebyscore testrank 0 0
(integer) 0
#根據值的權重(分數),從有序集合中移除符合條件的值;
127.0.0.1:6379> zremrangebyscore testrank 18 21
(integer) 1
127.0.0.1:6379> zscan testrank 0
1) "0"
2) 1) "3"
   2) "30"
127.0.0.1:6379> zadd testrank 0 a 0 b 0 c 0 d 0  e
(integer) 5
127.0.0.1:6379> zscan testrank 0
1) "0"
2)  1) "a"
    2) "0"
    3) "b"
    4) "0"
    5) "c"
    6) "0"
    7) "d"
    8) "0"
    9) "e"
   10) "0"
   11) "3"
   12) "30"
#當前有序集合中,所有分數都一樣時,根據設定的開閉區間,獲取區間內的值;
127.0.0.1:6379> zrangebylex testrank [a (d
(empty list or set)
127.0.0.1:6379> zrem testrank 3
(integer) 1
127.0.0.1:6379> zrangebylex testrank [aaa (e
1) "b"
2) "c"
3) "d"
127.0.0.1:6379> zrangebylex testrank [a (e
1) "a"
2) "b"
3) "c"
4) "d"
#當前有序集合中,所有分數都一樣時,根據設定的開閉區間,統計區間內的值個數;
127.0.0.1:6379> zlexcount testrank - +
(integer) 5
127.0.0.1:6379> zlexcount testrank (a (d
(integer) 2
#當前有序集合中,所有分數都一樣時,根據設定的開閉區間,刪除區間內的值;
127.0.0.1:6379> zremrangebylex testrank [a [c
(integer) 3
127.0.0.1:6379> zscan testrank 0
1) "0"
2) 1) "d"
   2) "0"
   3) "e"
   4) "0"


ZINTERSTORE 新集合 參與計算的集合個數 集合1 … [WEIGHTS 乘數1 …] [AGGREGATE 相同值的分數如何取值在(SUM|MIN|MAX)中選一個]
zunionstore與zinterstore的語法類似;
zunionstore/zinterstore與set類型中的類似都是將並集/交集存儲到新的集合中;
注意:
1.參與計算的集合個數必須與集合個數保持一致;
2.集合下標與乘數的下標會對應;(不設置乘數就默認是1)
… 例如:集合1 集合2 集合3 WEIGHTS 乘數1 乘數2 … 在運算的時候,集合1中分數 * 乘數1 集合2中分數 * 乘數2 集合3中分數*1;

  • HyperLogLog

簡稱HLL(這個實在不好讀),通常用來做計數,作用於集合類似,但是它不支持讀取內容;

#添加一個元素到一個hll中;成功返回1;
127.0.0.1:6379> pfadd testhll a b c
(integer) 1
#統計這個hll中有多少個元素,得到的就是計數(算上整個系統的延遲,通常是近似值);
127.0.0.1:6379> pfcount testhll
(integer) 3
127.0.0.1:6379> pfadd testhll1 d e f
(integer) 1
#合併兩個hll到一個hll;原來的hll還在;返回OK;如果合併後,原hll依然操作,這種情況下,合併後的hll不會變化;
127.0.0.1:6379> pfmerge testhll2 testhll testhll1
OK
127.0.0.1:6379> pfcount testhll2
(integer) 6
127.0.0.1:6379> pfcount testhll
(integer) 3
127.0.0.1:6379> pfcount testhll1
(integer) 3

  • Geo

地圖數據類型,裏面保存的都是經緯數值,有興趣的可以去官網看下;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章