【資料庫】Redis(2)--Redis的常用資料型別及命令
1.Redis主要資料型別分類
Redis中儲存資料常用的資料型別主要有五種:String、List、Set、Sorted Set、Hash,這五種資料結構在Redis中儲存資料的命令掌握對於我們後期在使用Java框架封裝類操作Redis的API瞭解是非常重要的。所以在這裡對這五種資料結構進行一一彙總,另外也簡單介紹一下bitmaps、hyperloglogs、geospatial這三種類型。
1.1.String型別
String型別在Redis中常用的操作:
①get/set/exists/append/strlen命令:
127.0.0.1:6379> set key1 v1 # 設定值 OK 127.0.0.1:6379> get key1 # 獲取值 "v1" 127.0.0.1:6379> keys * # 獲取所有的值 1) "key1" 127.0.0.1:6379> EXISTS key1 # 判斷key1是否存在 (integer) 1 127.0.0.1:6379> APPEND key1 "hello" # 向key1中追加"hello",如果Key1不存在,那就相當於set key1 (integer) 7 127.0.0.1:6379> get key1 "v1hello" 127.0.0.1:6379> STRLEN key1 #獲取字串的長度 (integer) 7 127.0.0.1:6379> APPEND key1 ", fengye" (integer) 15 127.0.0.1:6379> STRLEN key1 (integer) 15 127.0.0.1:6379> get key1 "v1hello, fengye"
②自增/減、步長(瀏覽量、點選數):
# +1/-1與+n/-n
127.0.0.1:6379> set views 0 OK 127.0.0.1:6379> get views "0" 127.0.0.1:6379> incr views # 自增+1 (integer) 1 127.0.0.1:6379> incr views (integer) 2 127.0.0.1:6379> get views "2" 127.0.0.1:6379> decr views # 自減-1 (integer) 1 127.0.0.1:6379> decr views (integer) 0 127.0.0.1:6379> decr views (integer) -1 127.0.0.1:6379> get views "-1" 127.0.0.1:6379> INCRBY views 10 # 增加 n (integer) 9 127.0.0.1:6379> INCRBY views 10 (integer) 19 127.0.0.1:6379> DECRBY views 5 # 減少 n (integer) 14
③字串擷取:
127.0.0.1:6379> set key1 "hello, fengye" OK 127.0.0.1:6379> get key1 "hello, fengye" 127.0.0.1:6379> GETRANGE key1 0 4 # 擷取閉區間 [0, 4]的字串 "hello" 127.0.0.1:6379> GETRANGE key1 0 -1 # 擷取全部的字串,和get key1同理 "hello, fengye"
④替換:
127.0.0.1:6379> set key2 abcddefg OK 127.0.0.1:6379> get key2 "abcddefg" 127.0.0.1:6379> SETRANGE key2 2 XXX # 替換指定位置開始的字串 (integer) 8 127.0.0.1:6379> get key2 "abXXXefg"
⑤setex(set with expire)與setnx(set if not exist):
#setex :設定過期時間
#setnx :不存在當前key才會設定值,在分散式鎖中常常使用
127.0.0.1:6379> setex key3 30 "hello" # 設定過期時間為30s,30s後過期 OK 127.0.0.1:6379> ttl key3 (integer) 21 127.0.0.1:6379> get key3 "hello" 127.0.0.1:6379> setnx mykey "redis" #設定mykey的值為redis,當mykey不存在時設定成功 (integer) 1 127.0.0.1:6379> keys * 1) "key1" 2) "key2" 3) "mykey" 127.0.0.1:6379> ttl key3 (integer) -2 127.0.0.1:6379> setnx mykey "mongoDb" #當mykey已經存在了,設定mykey會失敗 (integer) 0 127.0.0.1:6379> get mykey "redis"
⑥同時設定多個值mset/mget/msetnx:
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #同時設定多個值 OK 127.0.0.1:6379> keys * 1) "k3" 2) "k2" 3) "k1" 127.0.0.1:6379> mget k1 k2 k3 #同時獲取多個值 1) "v1" 2) "v2" 3) "v3" 127.0.0.1:6379> msetnx k1 y1 k4 v4 #同時獲取多個值,msetnx是一個原子性操作,要麼一起成功,要麼一起失敗
(integer) 0
127.0.0.1:6379> get k4
(nil)
⑦設定物件的值:
127.0.0.1:6379> set user:2 {name:lisi,age:3} # 使用json字串來儲存user的值 OK 127.0.0.1:6379> get user:2 "{name:lisi,age:3}" 127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2 # 使用user:1:name與user1:1:age來儲存值,user:{id}:{field}作為key來儲存值 OK 127.0.0.1:6379> mget user:1:name user:1:age 1) "zhangsan" 2) "2"
⑧getset(先獲取後設置):
127.0.0.1:6379> getset db redis #如果不存在值,則返回nil,並設定初始值 (nil) 127.0.0.1:6379> get db "redis" 127.0.0.1:6379> getset db mongodb #如果存在值,則返回那個值,並設定新的值 "redis" 127.0.0.1:6379> get db "mongodb"
1.2.List型別
①lpush/rpush/lrange(壓棧):
127.0.0.1:6379> LPUSH list one # 將一個或多個值放到列表的頭部(左push) (integer) 1 127.0.0.1:6379> LPUSH list two (integer) 2 127.0.0.1:6379> LPUSH list three (integer) 3 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "two" 3) "one" 127.0.0.1:6379> LRANGE list 0 1 1) "three" 2) "two" 127.0.0.1:6379> RPUSH list four # 將一個或多個值放到列表的尾部(右push) (integer) 4 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "two" 3) "one" 4) "four"
②lpop/rpop:
127.0.0.1:6379> LPOP list # 左移除列表中的一個元素 "three" 127.0.0.1:6379> RPOP list # 右移除列表中的一個元素 "four" 127.0.0.1:6379> LRANGE list 0 -1 1) "two" 2) "one"
③lindex(list index的簡寫):
127.0.0.1:6379> LINDEX list 1 # 通過下標獲得list中的某一個值 "one" 127.0.0.1:6379> LINDEX list 0 "two"
④llen:
127.0.0.1:6379> LPUSH list one (integer) 1 127.0.0.1:6379> LPUSH list two (integer) 2 127.0.0.1:6379> LPUSH list three (integer) 3 127.0.0.1:6379> Llen list # 返回列表的長度 (integer) 3
⑤Lrem:
127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "three" 3) "two" 4) "one" 127.0.0.1:6379> lrem list 1 one # 移除list集合中指定個數的元素,精確匹配個數並移除 (integer) 1 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "three" 3) "two" 127.0.0.1:6379> lrem list 1 three (integer) 1 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "two" 127.0.0.1:6379> LPUSH list three (integer) 3 127.0.0.1:6379> lrem list 2 three (integer) 2 127.0.0.1:6379> LRANGE list 0 -1 1) "two"
⑥Lrem:
127.0.0.1:6379> Rpush mylist "hello" (integer) 1 127.0.0.1:6379> Rpush mylist "hello1" (integer) 2 127.0.0.1:6379> Rpush mylist "hello2" (integer) 3 127.0.0.1:6379> Rpush mylist "hello3" (integer) 4 127.0.0.1:6379> Ltrim mylist 1 2 # 通過下標擷取指定的長度,擷取之後List會被改變,只剩下擷取後的元素 OK 127.0.0.1:6379> LRANGE list 0 -1 (empty list or set) 127.0.0.1:6379> LRANGE mylist 0 -1 1) "hello1" 2) "hello2"
⑦rpoplpush:
127.0.0.1:6379> rpush mylist "hello" (integer) 1 127.0.0.1:6379> rpush mylist "hello1" (integer) 2 127.0.0.1:6379> rpush mylist "hello2" (integer) 3 127.0.0.1:6379> rpoplpush mylist myotherlist #右彈棧,移除列表中最後一個元素並放入新的列表元素中 "hello2" 127.0.0.1:6379> lrange mylist 0 -1 1) "hello" 2) "hello1" 127.0.0.1:6379> lrange myotherlist 0 -1 1) "hello2"
⑧lset:
lset:將列表中指定下標的一個元素替換成另外一個元素,更新操作
127.0.0.1:6379> EXISTS list (integer) 0 127.0.0.1:6379> lset list 0 item #判斷列表是否存在,如果不存在的話,當前更新會報錯 (error) ERR no such key 127.0.0.1:6379> lpush list value1 (integer) 1 127.0.0.1:6379> LRANGE list 0 0 1) "value1" 127.0.0.1:6379> lset list 0 item #如果列表已經存在元素,可以更新當前列表中的元素 OK 127.0.0.1:6379> LRANGE list 0 0 1) "item" 127.0.0.1:6379> lset list 1 other #如果更新範圍超出限制,也會丟擲異常 (error) ERR index out of range
⑨Linsert:
Linsert將某一個具體的value插入到列表中的某個元素的前面或者後面
127.0.0.1:6379> Rpush mylist "hello" (integer) 1 127.0.0.1:6379> Rpush mylist "world" (integer) 2 127.0.0.1:6379> LINSERT mylist before "world" "other" (integer) 3 127.0.0.1:6379> LRANGE mylist 0 -1 1) "hello" 2) "other" 3) "world" 127.0.0.1:6379> LINSERT mylist after "world" "new" (integer) 4 127.0.0.1:6379> LRANGE mylist 0 -1 1) "hello" 2) "other" 3) "world" 4) "new"
1.3.Set型別
redis中Set集合中的元素是不能重複的。
①sadd/smembers/sismember/scard
127.0.0.1:6379> sadd myset "hello" (integer) 1 127.0.0.1:6379> sadd myset "fengye" (integer) 1 127.0.0.1:6379> sadd myset "love fengye" (integer) 1 127.0.0.1:6379> SMEMBERS myset #檢視myset中所有的值 1) "fengye" 2) "love fengye" 3) "hello"127.0.0.1:6379> SISMEMBER myset hello #判斷某一個值是不是在set集合中 (integer) 1 127.0.0.1:6379> SISMEMBER myset world (integer) 0
127.0.0.1:6379> scard myset #獲取set集合中內容元素的個數
(integer) 4
②srem
127.0.0.1:6379> SMEMBERS myset 1) "fengye" 2) "lovekuangshen2" 3) "love fengye" 4) "hello" 127.0.0.1:6379> srem myset lovekuangshen2 #移除某一個元素 (integer) 1 127.0.0.1:6379> SMEMBERS myset 1) "fengye" 2) "love fengye" 3) "hello"
③srandmember
127.0.0.1:6379> SRANDMEMBER myset "hello" 127.0.0.1:6379> SRANDMEMBER myset "love fengye" 127.0.0.1:6379> SRANDMEMBER myset "fengye" 127.0.0.1:6379> SRANDMEMBER myset 2 #隨機抽選出指定個數的元素 1) "hello" 2) "love fengye"
④spop
127.0.0.1:6379> spop myset #隨機刪除集合中的一些元素 "fengye" 127.0.0.1:6379> spop myset "love fengye" 127.0.0.1:6379> SMEMBERS myset 1) "hello"
⑤smove
127.0.0.1:6379> sadd myset "hello" (integer) 1 127.0.0.1:6379> sadd myset "world" (integer) 1 127.0.0.1:6379> sadd myset "fengye" (integer) 1 127.0.0.1:6379> sadd myset2 "set2" (integer) 1 127.0.0.1:6379> smove myset myset2 "fengye" #將指定的元素從一個set移動到另一個set集合中 (integer) 1 127.0.0.1:6379> SMEMBERS myset 1) "world" 2) "hello" 127.0.0.1:6379> SMEMBERS myset2 1) "fengye" 2) "set2"
⑥sdiff/sinter/sunion
127.0.0.1:6379> sadd key1 a (integer) 1 127.0.0.1:6379> sadd key1 b (integer) 1 127.0.0.1:6379> sadd key1 c (integer) 1 127.0.0.1:6379> sadd key2 c (integer) 1 127.0.0.1:6379> sadd key2 d (integer) 1 127.0.0.1:6379> sadd key2 e (integer) 1 127.0.0.1:6379> SDIFF key1 key2 # 差集 1) "a" 2) "b" 127.0.0.1:6379> SINTER key1 key2 # 交集 1) "c" 127.0.0.1:6379> SUNION key1 key2 # 並集 1) "a" 2) "b" 3) "c" 4) "d" 5) "e"
1.4.Hash
①hset/hget/hmget/hgetall:
127.0.0.1:6379> hset myhash field1 fengye # hset一個具體的key-value (integer) 1 127.0.0.1:6379> hget myhash field1 "fengye" 127.0.0.1:6379> hmset myhash field1 hello field2 world #set多個key value OK 127.0.0.1:6379> hmget myhash field1 field2 #獲取多個欄位值 1) "hello" 2) "world" 127.0.0.1:6379> hgetall myhash #獲取全部的資料 1) "field1" 2) "hello" 3) "field2" 4) "world"
#使用hash存取物件資料
127.0.0.1:6379> hmset myhash username zhangsan sex '男' age 24
OK
127.0.0.1:6379> HGETALL myhash
1) "field2"
2) "world"
3) "field1"
4) "hello"
5) "field3"
6) "5"
7) "filed3"
8) "1"
9) "field4"
10) "hello"
11) "username"
12) "zhangsan"
13) "sex"
14) "\xe7\x94\xb7"
15) "age"
16) "24"
②hdel:
127.0.0.1:6379> hdel myhash field1 #刪除hash中指定的key欄位,對應的value值也就沒有了 (integer) 1 127.0.0.1:6379> hgetall myhash 1) "field2" 2) "world"
③hlen:
127.0.0.1:6379> HGETALL myhash 1) "field2" 2) "world" 3) "field1" 4) "hello" 127.0.0.1:6379> hlen myhash # 獲取hash表的欄位數量 (integer) 2
④hexists:
127.0.0.1:6379> HEXISTS myhash field1 #判斷hash中的key是否存在 (integer) 1 127.0.0.1:6379> HEXISTS myhash field3 (integer) 0
⑤Hkeys/Hvals:
127.0.0.1:6379> HKEYS myhash # 查詢所有的keys 1) "field2" 2) "field1" 127.0.0.1:6379> HVALS myhash # 查詢所有的vals 1) "world" 2) "hello"
⑥hincrby/hsetnx:
127.0.0.1:6379> hset myhash field3 5 (integer) 1 127.0.0.1:6379> HINCRBY myhash field3 1 #hash指定增量 (integer) 6 127.0.0.1:6379> HINCRBY myhash field3 -1 #hash自減 (integer) 5 127.0.0.1:6379> hsetnx myhash field4 hello #不存在則設定值 (integer) 1 127.0.0.1:6379> hsetnx myhash field4 world #存在則無法設定,分散式鎖 (integer) 0
1.5.Sorted Set有序集合類
①zadd/zrange:
127.0.0.1:6379> zadd myset 1 one #新增一個值 (integer) 1 127.0.0.1:6379> zadd myset 2 two 3 three #新增多個值 (integer) 2 127.0.0.1:6379> ZRANGE myset 0 -1 1) "one" 2) "two" 3) "three"
②zrangebyscore:
127.0.0.1:6379> clear 127.0.0.1:6379> zadd salary 2500 xiaohong (integer) 1 127.0.0.1:6379> zadd salary 4000 zhangsan (integer) 1 127.0.0.1:6379> zadd salary 1000 fengye (integer) 1 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf #按照薪資高低升序排序 1) "fengye" 2) "xiaohong" 3) "zhangsan" 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores #按照薪資高低升序排序,附帶薪資
1) "fengye"
2) "1000"
3) "xiaohong"
4) "2500"
5) "zhangsan"
6) "4000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores
1) "fengye"
2) "1000"
3) "xiaohong"
4) "2500"
③zrem:
127.0.0.1:6379> ZREM salary zhangsan #移除sorted set中指定的元素 (integer) 1 127.0.0.1:6379> ZRANGE salary 0 -1 1) "fengye"
④zcard:
127.0.0.1:6379> ZCARD salary #獲取有序集合中元素的個數 (integer) 2
⑤zrevrage:
127.0.0.1:6379> ZREVRANGE salary 0 -1 withscores #從大到小排列 1) "xiaohong" 2) "2500" 3) "fengye" 4) "1000"
⑥zcount:
127.0.0.1:6379> zadd myset 1 hello (integer) 1 127.0.0.1:6379> zadd myset 2 world 3 fengye (integer) 2 127.0.0.1:6379> zcount myset 1 3 #獲取指定區間的成員數量 (integer) 3 127.0.0.1:6379> zcount myset 1 2 (integer) 2
2.Redis幾種特殊型別分類
2.1.Geospatial地理位置
Redis通過Geospatial可以根據地理位置如經度、緯度查詢出兩地之間的距離。主要分為以下幾個命令:
①geoadd:
# 新增規則:除兩極不能新增外,其它均能新增
# 引數 key 經度 緯度 名稱
# 有效的經度從-180度到180度
# 有效的緯度從-85.05112878度到85.05112878度
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing (integer) 1 127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai # 新增地理位置 (integer) 1 127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqi 114.05 22.52 shengzhen (integer) 2 127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian (integer) 2
②geopos:
127.0.0.1:6379> geopos china:city beijing # 獲取指定的成員的經度和緯度 1) 1) "116.39999896287918091" 2) "39.90000009167092543" 127.0.0.1:6379> geopos china:city beijing xian 1) 1) "116.39999896287918091" 2) "39.90000009167092543" 2) 1) "108.96000176668167114" 2) "34.25999964418929977"
③geodist:
計算兩個城市地區之間的直線距離:
- m表示單位米
- km表示單位千米
- mi表示單位英里
- ft表示單位英尺
127.0.0.1:6379> geodist china:city beijing shanghai "1067378.7564" 127.0.0.1:6379> geodist china:city beijing shanghai km # 查詢北京到上海的直線距離,單位km "1067.3788" 127.0.0.1:6379> geodist china:city beijing hangzhou km "1127.3378"
④georadius:
以給定的經緯度為中心,找出某一半徑內的元素:
127.0.0.1:6379> GEORADIUS china:city 110.35 30.39 1000 km #獲取當前經度緯度下1000km以內的城市 1) "chongqi" 2) "xian" 3) "shengzhen" 4) "hangzhou" 127.0.0.1:6379> GEORADIUS china:city 110.35 30.39 500 km 1) "chongqi" 2) "xian" 127.0.0.1:6379> GEORADIUS china:city 110.35 30.39 500 km withdist #獲取該經度緯度下500km以內的城市並附帶距離 1) 1) "chongqi" 2) "383.1094" 2) 1) "xian" 2) "449.8190" 127.0.0.1:6379> GEORADIUS china:city 110.35 30.39 500 km withcoord #獲取該經度緯度下500km以內的城市病顯示城市的經度、緯度 1) 1) "chongqi" 2) 1) "106.49999767541885376" 2) "29.52999957900659211" 2) 1) "xian" 2) 1) "108.96000176668167114" 2) "34.25999964418929977" 127.0.0.1:6379> GEORADIUS china:city 110.35 30.39 500 km withdist withcoord count 2 #count 2表示只顯示2個 1) 1) "chongqi" 2) "383.1094" 3) 1) "106.49999767541885376" 2) "29.52999957900659211" 2) 1) "xian" 2) "449.8190" 3) 1) "108.96000176668167114" 2) "34.25999964418929977"
⑤georadiusbymember:
127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 400 km #以城市為中心查詢出距離400km的城市 1) "hangzhou" 2) "shanghai"
⑥geohash:
該命令將返回11個字元的geohash字串
127.0.0.1:6379> geohash china:city beijing chongqi 1) "wx4fbxxfke0" 2) "wm5xzrybty0"
⑦zset命令刪除:
geo底層就是zset,所以我們可以使用zset進行刪除:
127.0.0.1:6379> ZRANGE china:city 0 -1 1) "chongqi" 2) "xian" 3) "shengzhen" 4) "hangzhou" 5) "shanghai" 6) "beijing" 127.0.0.1:6379> ZREM china:city beijing (integer) 1
2.2.hyperloglogs
Redis基於hyperloglogs提供了一種更高效的演算法來計算兩個集合中的元素個數,重複個數不累計。
這種高效率的演算法替代了傳統使用set集合進行不重複元素的存取計算方式。
hyperloglogs的優點:
- 佔用記憶體小,存取2^64的不同元素的基數,只需要12kb的記憶體儲存空間
127.0.0.1:6379> PFADD mykey a b c d e f g h i j (integer) 1 127.0.0.1:6379> PFCOUNT mykey (integer) 10 127.0.0.1:6379> PFADD mykey2 i j z x c a b n m (integer) 1 127.0.0.1:6379> PFCOUNT mykey2 (integer) 9 127.0.0.1:6379> PFMERGE mykey3 mykey mykey2 #合併兩個集合的元素 OK 127.0.0.1:6379> PFCOUNT mykey3 #計算元素的個數,不重複 (integer) 14
注意:使用hyperloglogs有0.81%的錯誤率,如果不允許容錯,需要精確計算的,則不能使用hyoerloglogs。
2.3.Bitmaps型別
Bitmaps使用位0 1進行資料的儲存。
適用場景:統計使用者資訊,活躍與非活躍、登入、打卡
使用Bitmaps來記錄一週7天的打卡時間:
127.0.0.1:6379> setbit sign 0 1 (integer) 0 127.0.0.1:6379> setbit sign 1 0 (integer) 0 127.0.0.1:6379> setbit sign 2 0 (integer) 0 127.0.0.1:6379> setbit sign 3 1 (integer) 0 127.0.0.1:6379> setbit sign 4 1 (integer) 0 127.0.0.1:6379> setbit sign 5 0 (integer) 0 127.0.0.1:6379> setbit sign 6 0 (integer) 0 127.0.0.1:6379> getbit sign 3 #檢視某一天是否有打卡 (integer) 1 127.0.0.1:6379> getbit sign 6 (integer) 0
127.0.0.1:6379> BITCOUNT sign #統計打卡的天數
(integer) 3
&n