1.字符串類型:string
字符串類型是Redis中最基本的數據類型,他能存儲任何形式的字符串,包括二進制數據。 **一個字符串類型的鍵允許存儲的數據最大容量是512MB。**
字符串類型可以用來存儲用戶的信息如郵箱、JSON化的對象甚至一張圖片。
1.1 命令
首先需要說明的是,在Redis中,所有的redis命令都是原子操作,包括后面提到的遞增命令 incr 等。
1.取值與復制:
set key value
get key
重新給存在的key賦值時會覆蓋原有value;取值時,當key不存在時會返回空結果。
例子:
127.0.0.1:6379[1]> set name hello
OK
127.0.0.1:6379[1]> get name
"hello"
127.0.0.1:6379> set name okok
OK
127.0.0.1:6379> get name
"okok"
127.0.0.1:6379> get newName
(nil)
2.遞增數字
當存儲的字符串是整數的形式時,其實Redis提供了一個實用的命令 incr ,其作用是讓當前的鍵值遞增,並返回遞增后的值。
127.0.0.1:6379> incr num
(integer) 1
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> get num
"2"
當 incr 的 key 不存在時,默認的鍵值是 0 ,所以第一次遞增后的結果是 1 。當 incr 的 key 的值 不是整數時會報錯。
127.0.0.1:6379> set eg hello
OK
127.0.0.1:6379> get eg
"hello"
127.0.0.1:6379> incr eg
(error) ERR value is not an integer or out of range
3.其他命令
1.增加指定的整數:incrby key num
2.讓值遞減:decr key
3.減少指定的整數:decrby key num (相當於:incrby key -num)
4.向尾部追加值:append key add_value (key不存在相當於set操作,key存在相當於字符串尾部拼接,返回值是字符串拼接后長度)
5.獲取字符串長度:strlen key (鍵不存在返回 0 )
127.0.0.1:6379> set word 你好
OK
127.0.0.1:6379> strlen word
(integer) 6
127.0.0.1:6379> get word
"\xe4\xbd\xa0\xe5\xa5\xbd"
由於可存儲任何類型的字符串,如上若utf-8編碼的中文,“你”、“好”兩個字的utf-8編碼長度都是3,所以返回的長度是6。
6.同時設置/獲取多個鍵值:
mset key1 v1 key2 v2 key3 v3
mget key1 key2 key3
7.位操作:
getbit key offset
setbit key offset value
bitcount key [start] [end]
bitop operation destkey key [key key ...]
1個字節是8個二進制位,Redis提供了4個命令可以直接對二進制位進行操作。具體說明見博客:https://www.cnblogs.com/lxhyty/p/11364557.html
利用為操作命令可以非常緊湊的存儲布爾值。比如某網站的每個用戶都有一個遞增的整數ID,如果使用一個字符串類型的鍵配合位造作來記錄每個用戶的性別(或是否在線等),用戶ID作為索引,對應二進制位的1、0表示男、女(在線、離線)。那么記錄100萬個用戶的信息只需要100多KB的空間,且由於getbit、setbit的時間復雜度是O(1),所以讀取操作二進制位的性能很高。
1.2 實踐
1.文章訪問量統計
很容易想到,做訪問量統計的時候,我們可以使用 incr 來遞增訪問量的值。
Redis對於key的命名沒有強制的要求,但比較好的命名格式是“對象類型:對象ID:對象屬性” ,如使用鍵user:1:friends來存儲ID為1的用戶的好友列表。在需要有多個單詞來表示時推薦使用“.”來分割,而不是在編程時的駝峰命名,如文章的訪問量的key我們是post:24:page.view ,每次訪問量遞增使用命令 incr post:24:page.view 。
2.生成自增ID
在關系型數據庫中我們設置文章的ID字段屬性為AUTO_INCREAMENT來實現自動為每篇文章生成唯一ID,而在Redis中可以通過另一種方式來實現,對每一類對象設置鍵為“對象類型(復數形式):count”來存儲當前類型對象的數量,然后使用 incr 來增加該鍵的值,返回值即是新增對象的ID。
3.存儲文章數據
一篇文章是由標題、作者、正文等多個元素組成的。為了用字符串類型的鍵值存儲這些元素,我們需要用到序列化函數將他們轉換成一個字符串。(因為字符串類型可以存儲二進制數據,所以也可以使用MessagePack進行序列化,速度更快,占用空間也更小。)
至此,我們在某一門編程語言中可以有如下操作:(偽代碼)
# 獲取新文章的ID
postID = incr posts:count
# 將博客文章多個元素序列化成字符串
postData = serialize(title,content,autor,createdtime)
# 把序列化的字符串存入一個字符串類型的鍵中
set post:postID:data postData
2.散列類型:hash
散列類型的鍵值也是一種字典結構,其存儲了字段和字段值的映射,一個散列類型鍵最多可以包含 (2^32)-1 個字段。字段值只能是字符串,不能是其他類型。同所有的redis數據類型一樣,散列類型也不能嵌套其他數據類型。
散列類型適合存儲對象。使用對象類別和對象ID構成 key ,使用 字段和字段值 表示對象的屬性。另外在Redis中同一類對象可以有不同的字段。如對象 user:1 有字段 name、passward、money,而對象user:2除此之外還可以單獨有字段email等。
2.1命令
1.復制與取值
hset 用來給新建 哈希鍵值,也可以用來給字段賦值,hget 用來獲取字段的值。
hset key field1 value1 [field2 value2 field3 value3 ...] # 新建哈希鍵值
hset key field value # 給哈希設置單個字段
hmset key field1 value1 [field2 value2 ...] # 同時設置多個字段
hget key field # 獲取單個字段值
hgetall key # 獲取所有字段值
hmget key field1 [field2 field3 ...] # 同時獲取多個字段值
hset 命令不區分更新和插入操作,所以無需額外判斷字段是否存在來決定進行插入還是更新操作。當字段不存在,執行的是插入操作,hset 命令會返回 1 ,字段存在,執行的是更新操作,hset 命令返回 0 。甚至當哈希鍵本身不存在的時候還會自動建立它。
2.判斷字段存在
hexists key field (判斷字段是否存在:存在則返回 1 ,不存在則會返回 0 )
hsetnx key field value (當字段存在,不執行任何操作,返回 0 。字段不存在則賦值,返回 1 )
再次聲明,這些命令都是原子操作,不必擔心競爭操作導致出錯。
3.增加數字
hincrby key field num
# 與字符串類型的增加數字的 incrby 相似,散列類型沒有 hincr ,要實現加一的功能可以用 hincrby key field 1
# 當key或者字段field不存在時,都會自動的建立它,建立的字段在執行命令前初始整數值是 0 ,返回值是增加值之后的值。
4.刪除字段
hdel key field1 [field2 field3 ...]
# 這條命令可以刪除一個或者多個字段,返回值是被刪除的字段的個數。刪除不存在的字段,返回值是 0 。
5.其他命令
1.只獲取字段名:hkeys key
2.只獲取字段值:hvals key
3.獲取字段數量:hlen key
2.2 實踐
1.存儲文章數據
在上面我們將整個文章對象序列化后用一個字符串類型來存儲,他無法對文章的某個屬性做原子操作,如兩個客戶端同時獲取並反序列化一篇文章,然后修改不同的屬性后存入,那么后一個修改會覆蓋前一個修改,最后只有一個屬性被修改成功。另外在我們只需要對象的部分屬性時,我們也不得不把整個對象取出來操作,比較消耗資源。
這里我們就可以使用哈希類型來存儲文章對象了。如:
hset post:1001 title 第一篇文章 author admin content 這是我的第一篇文章 time 2019-8-15
# 只獲取文章標題
hget post:1001 title
# 修改文章標題
hset post:1001 title 修改后的第一篇文章
其實存儲同樣的數據,散列類型往往比字符串類型更加節約空間,這和redis數據類型的底層實現有關。
3.列表類型:list
列表類型可以存儲一個有序的字符串列表,常用的操作是向列表的兩端添加元素,或者獲得列表的某一個片段。與散列類型一樣,一個列表類型最多能容納 (2^32)-1 個元素。
Redis的列表內部是使用雙向鏈表實現的,所以在列表兩端操作元素的時間復雜度為O(1),獲取越接近兩端的元素速度越快。不過使用鏈表的代價是通過索引訪問元素比較慢。由於可以在兩端操作,我們可以將其作為隊列或者棧來使用。
3.1 命令
1.向列表兩端添加元素:
lpush key value [value value ...] # 在列表左端添加元素
rpush key value [value value ...] # 在列表右端添加元素
# 返回值是 增加元素后的列表長度。
2.從列表兩端彈出元素:
lpop key # 從列表左端彈出元素
rpop key # 從列表右端彈出元素
# 返回值是被彈出的元素
3.獲取列表元素個數:
llen key # 注意是兩個"l"字母
這個命令的時間復雜度是O(1),因為列表直接存儲了當前元素的個數,使用時Redis會直接讀取現成的值,而不需要像部分關系數據庫那樣遍歷一次數據表。
4.獲取列表片段:
lrange key start stop # 從列表左端開始獲取列表片段
# 返回索引從start到stop之間的所有元素,包括了start和stop本身的元素(即閉區間)。
列表的起始索引是0,lrange命令也支持負索引,表示從列表右端開始計算次序,如"-1"表示最右邊第一個元素,"-2"表示最右邊倒數第二個元素,以此類推。如:lrange key -3 -1 表示返回列表的最右邊的三個元素。
注意:
(1) 如果start比stop大,則返回空列表。
(2) 如果stop大於實際索引范圍,則會返回到列表最右邊的元素。
5.刪除列表中指定的值:
lrem key count value
# 刪除列表中前count個值為value的元素,返回實際被刪除的元素的個數。
當 count > 0 時,從列表左端開始刪除。
當 count < 0 時,從列表右端開始刪除。
當 count = 0 時,刪除列表所有值為value的元素。
6.其他命令:
1.獲取指定索引的元素值:lindex key index
2.設置指定索引的元素值:lset key index value
3.只保留列表的指定片段:ltrim key start stop (刪除start之前和stop之后的所有元素)
4.向列表插入元素:linsert key before|after pivot value
在列表中從左開始查找值為pivot的元素,然后根據是before還是after決定在它前面還是后面插入value,返回插入后元素的個數。
5.將元素從一個列表轉移到另一個列表:rpoplpush lista listb (從lista彈出最右端的元素添加到listb的左邊,返回值是這個元素的值)
3.2 實踐
列表可以用來存儲如文章ID,以實現顯示文章列表、文章列表分頁的目的,存儲評論列表等。因為是雙向鏈表實現,有隊列棧的特性,在一些場合也非常適用,如“新鮮事”,“日志”等,他們很少訪問中間元素。
4.集合類型:set
集合中每個元素都不相同,且沒有順序。一個集合類型最多可以存儲 (2^32)-1 個字符串。
集合類型在Redis內部是使用值為空的散列表(hash table)實現的,所以添加、刪除、判斷等操作時間復雜度都是O(1)。多個集合之間也可以進行並集、交集、差集運算。
4.1 命令
1.增加/刪除元素:
sadd key value [value ...] # 添加元素,key不存在時自動創建。返回值是成功加入的元素個數。
srem key value [value ...] # 刪除元素,返回值是成功刪除的元素個數。
2.獲取集合所有元素:
smembers key
3.判斷某個元素是否在集合中:
sismember key value # 存在時返回 1 ,不存在時返回 0
4.集合運算:
sdiff key1 [key2 ...] # 差集運算。運算結果為:key1 - key2 - ...
sinter key1 [key2 ...] # 交集運算。運算結果為:key1 n key2 n ...
sunion key1 [key2 ...] # 並集運算。運算結果為:key1 u key2 u ...
5.其他命令:
1.獲取集合元素的個數:scard key
2.從集合彈出一個元素:spop key (隨機彈出一個元素)
3.隨機獲取集合中的元素:srandmember key [count] (count可以指定獲取的元素個數,不寫則默認獲取一個元素)
4.進行集合運算並將結果存儲:
sdiffstore res key1 [key2 ...] # 差集運算。運算結果存儲在集合 res 中
sinterstore res key1 [key2 ...] # 交集運算。運算結果存儲在集合 res 中
sunionstore res key1 [key2 ...] # 並集運算。運算結果存儲在集合 res 中
4.2 實踐
集合可以存儲如文章標簽等數據,通過標簽來查詢文章。
5.有序集合類型:zset
在集合的基礎上為每個元素都關聯了一個分數,以此來實現有序。可以獲取分數最高(最低)的前N個元素、獲取指定分數范圍內的元素等與分數有關的操作。雖然集合中每個元素不同但他們的分數可以相同。
列表通過鏈表實現,所以獲取中間元素較慢,但有序集合類型是使用散列表和跳躍表實現的,所以即使讀取位於中間的數據速度也會很快(時間復雜度O(log(N)))。有序集合可以通過調整元素的分數來簡單的改變元素的位置。有序集合比列表更加耗費內存。
5.1 命令
1.增加元素:
zadd key score member [score member ...]
若加入的元素已經存在,則只會更新它的分數,zadd 返回值是成功新加入有序集合的元素個數(更新分數不算)。這個分數可以是整數也可以是雙精度浮點數,另外"+inf"和"-inf"表示正無窮和負無窮。
2.獲取元素的分數:
zscore key member
3.獲取在某個位置區間的元素列表:
zrange key start stop [withscore] # 結果按照分數從小到大排列
zrerange key start stop [withscore] # 結果按照分數從大到小排列
zrange命令的時間復雜度是O(logn+m)。它與lrange命令相似,都是閉區間,可用負索引。如果排列結果要加上分數則命令尾部加上 withscore 。
4.獲取指定分數范圍的元素:
zrangebyscore key min max [withscore] [limit offset count]
該命令按從小到大的順序返回分數在min和max(包括min、max)之間的元素。如果希望不包含端點值,即開區間,可以在分數前加上"("符號,如:zrangebyscore grad 80 (100
與sql語句一樣,limit offset count 表示在獲取到的元素列表的基礎上向后便宜offset個元素,且只獲取前count個元素。
5.增加某個元素的分數:
zincrby key num member # num表示給member增加的分數,可以是負數表示減分數。
6.其他命令:
1.獲取集合中元素的數量:zcard key
2.獲取指定分數范圍內的元素個數:zcount key min max (閉區間)
3.刪除一個或多個元素:zrem key member [member ...] (返回值是成功刪除元素的個數)
4.刪除指定位置內的元素:zremrangebyrank key start stop (命令按照分數從小到大的順序刪除第start個到stop的元素,返回成功刪除的元素個數)
5.刪除指定分數范圍內的元素:zremrangebyscore key min max (返回成功刪除的元素個數)
6.獲取元素的位置:
zrank key member (從小到大的順序排列的位置)
zrevrank key member (從大到小的順序排列的位置)
7.有序集合的集合運算:
zunionscore res numkeys key [key ...] (計算給定的一個或多個有序集的並集,並存儲在 res 中)
zinterscore res numkeys key [key ...] (計算給定的一個或多個有序集的交集並將結果集存儲在新的有序集合 res 中)
5.2 實踐
有序集合類型,很方便的實現如熱評,點擊量排序,時間排序等。