原文鏈接:http://www.cnblogs.com/xrq730/p/8944539.html,轉載請注明出處,謝謝
本文目錄
上一篇文章以認識Redis為主,寫了Redis系列的第一篇,現在開啟第二部分的學習,在本文中,我們將看到以下內容:
- Redis數據結構String、Hash、List、Set、SortedSet及相關操作,提一下Redis在3.2.0之后有新增了一種GEO的數據類型表示地理位置,不過本文這種數據結構略過
- Redis其他一些常用命令,分為Key操作與服務器操作
- Redis事務機制
主要以實戰為主,希望通過本文可以讓大家掌握Redis的基本使用。
本來這篇文章還准備加上Redis線程模型分析的,但是寫完發現篇幅實在太長,就把Redis線程模型放到最后一篇中了,也挺好的,本文專注於對Redis命令的講解。
另外說一下,本文講Redis中的數據結構,但是數據結構本身不在本文的講解范圍內,如果想知道Hash、List、Set等數據結構特點及使用場景,可以自己查閱數據結構相關資料。
String數據結構的基本操作
首先說一下數據結構String,這是Redis中最簡單的一種數據結構,和MemCache數據結構是一樣的,即Key-Value型的數據,根據Redis官方文檔,Value最大值為512M。
下面用表格來看一下String操作的相關命令:
| 命令 | 描述 | 用法 |
| SET | (1)將字符串值Value關聯到Key (2)Key已關聯則覆蓋,無視類型 (3)原本Key帶有生存時間TTL,那么TTL被清除 |
SET key value [EX seconds] [PX milliseconds] [NX|XX] |
| GET | (1)返回key關聯的字符串值 (2)Key不存在返回nil (3)Key存儲的不是字符串,返回錯誤,因為GET只用於處理字符串 |
GET key |
| MSET | (1)同時設置一個或多個Key-Value鍵值對 (2)某個給定Key已經存在,那么MSET新值會覆蓋舊值 (3)如果上面的覆蓋不是希望的,那么使用MSETNX命令,所有Key都不存在才會進行覆蓋 (4)MSET是一個原子性操作,所有Key都會在同一時間被設置,不會存在有些更新有些沒更新的情況 |
MSET key value [key value ...] |
| MGET | (1)返回一個或多個給定Key對應的Value (2)某個Key不存在那么這個Key返回nil |
MGET key [key ...] |
| SETEX | (1)將Value關聯到Key (2)設置Key生存時間為seconds,單位為秒 (3)如果Key對應的Value已經存在,則覆蓋舊值 (4)SET也可以設置失效時間,但是不同在於SETNX是一個原子操作,即關聯值與設置生存時間同一時間完成 |
SETEX key seconds value |
| SETNX | (1)將Key的值設置為Value,當且僅當Key不存在 (2)若給定的Key已經存在,SEXNX不做任何動作 |
SETNX key value |
首先,演示一下SET、GET、SETEX的效果:

圖中我們應該能看到SET、GET、SETNX幾個命令的效果了,在這之外,專門提兩點:
- Redis的命令不區分大小寫
- Redis的Key區分大小寫
接着我們演示一下SETEX命令的效果:

這里順帶介紹了TIME命令,它返回的是當前服務器Unix時間戳,但單位為秒(通常Unix時間戳取的時間為毫秒)。看到設置Redis-Expire這個Key,馬上獲取不失效,第26秒獲取的時候失效,關於失效,Redis的策略是這樣的:
- 被動觸發,即GET的時候檢查一下Key是否失效
- 主動觸發,后台每1秒跑10次定時任務(通過redis.conf的hz參數配置,默認為10,這個上文沒有寫),隨機選擇100個設置了過期時間的Key,對過期的Key進行失效
最后看一下MGET和MSET命令:

看到可以同時設置多個Key-Value,也可以同時獲取多個Key對應的Value,再次注意,Redis的Key是嚴格區分大小寫的。
特殊的String操作:INCR/DECR
前面介紹的是基本的Key-Value操作,下面介紹一種特殊的Key-Value操作即INCR/DECR,可以利用Redis自動幫助我們對一個Key對應的Value進行加減,用表格看一下相關命令:
| 命令 | 描述 | 用法 |
| INCR | (1)Key中存儲的數字值+1,返回增加之后的值 (2)Key不存在,那么Key的值被初始化為0再執行INCR (3)如果值包含錯誤類型或者字符串不能被表示為數字,那么返回錯誤 (4)值限制在64位有符號數字表示之內,即-9223372036854775808~9223372036854775807 |
INCR key |
| DECR | (1)Key中存儲的數字值-1 (2)其余同INCR |
DECR key |
| INCRBY | (1)將key所存儲的值加上增量返回增加之后的值 (2)其余同INCR |
INCRBY key increment |
| DECRBY | (1)將key所存儲的值減去減量decrement (2)其余同INCR |
DECRBY key decrement |
下面實際看一下四個命令相關使用:

INCR/DECR在實際工作中還是非常管用的,舉兩個例子:
- 原先單機環境中統計在線人數,變成分布式部署之后可以使用INCR/DECR
- 由於Redis本身極高的讀寫性能,一些秒殺的場景庫存增減可以基於Redis來做而不是直接操作DB
Hash數據結構相關操作
接着講一下Hash,Hash本質上和String是一樣的,無非String是純粹的Key-Value,Hash是外面套了一層東西,里面還是Key-Value,接着我們用表格看一下Hash數據結構的相關命令:
| 命令 | 描述 | 用法 |
| HSET | (1)將哈希表Key中的域field的值設為value (2)key不存在,一個新的Hash表被創建 (3)field已經存在,舊的值被覆蓋 |
HSET key field value |
| HGET | (1)返回哈希表key中給定域field的值 | HGET key field |
| HDEL | (1)刪除哈希表key中的一個或多個指定域 (2)不存在的域將被忽略 |
HDEL key filed [field ...] |
| HEXISTS | (1)查看哈希表key中,給定域field是否存在,存在返回1,不存在返回0 | HEXISTS key field |
| HGETALL | (1)返回哈希表key中,所有的域和值 | HGETALL key |
| HINCRBY | (1)為哈希表key中的域field加上增量increment (2)其余同INCR命令 |
HINCRYBY key filed increment |
| HKEYS | (1)返回哈希表key中的所有域 | HKEYS key |
| HLEN | (1)返回哈希表key中域的數量 | HLEN key |
| HMGET | (1)返回哈希表key中,一個或多個給定域的值 (2)如果給定的域不存在於哈希表,那么返回一個nil值 |
HMGET key field [field ...] |
| HMSET | (1)同時將多個field-value對設置到哈希表key中 (2)會覆蓋哈希表中已存在的域 (3)key不存在,那么一個空哈希表會被創建並執行HMSET操作 |
HMSET key field value [field value ...] |
| HVALS | (1)返回哈希表key中所有的域和值 | HVALS key |
同樣的,實際看一下這些命令的相關使用:

稍亂,但是除了HMSET、HMGET以外把所有命令都演示到了。
List數據結構相關操作
接着我們看一下Redis中的List,相關命令有:
| 命令 | 描述 | 用法 |
| LPUSH | (1)將一個或多個值value插入到列表key的表頭 (2)如果有多個value值,那么各個value值按從左到右的順序依次插入表頭 (3)key不存在,一個空列表會被創建並執行LPUSH操作 (4)key存在但不是列表類型,返回錯誤 |
LPUSH key value [value ...] |
| LPUSHX | (1)將值value插入到列表key的表頭,當且晉檔key存在且為一個列表 (2)key不存在時,LPUSHX命令什么都不做 |
LPUSHX key value |
| LPOP | (1)移除並返回列表key的頭元素 |
LPOP key |
| LRANGE | (1)返回列表key中指定區間內的元素,區間以偏移量start和stop指定 (2)start和stop都以0位底 (3)可使用負數下標,-1表示列表最后一個元素,-2表示列表倒數第二個元素,以此類推 (4)start大於列表最大下標,返回空列表 (5)stop大於列表最大下標,stop=列表最大下標 |
LRANGE key start stop |
| LREM | (1)根據count的值,移除列表中與value相等的元素 (2)count>0表示從頭到尾搜索,移除與value相等的元素,數量為count (3)count<0表示從從尾到頭搜索,移除與value相等的元素,數量為count (4)count=0表示移除表中所有與value相等的元素 |
LREM key count value |
| LSET | (1)將列表key下標為index的元素值設為value (2)index參數超出范圍,或對一個空列表進行LSET時,返回錯誤 |
LSET key index value |
| LINDEX | (1)返回列表key中,下標為index的元素 |
LINDEX key index |
| LINSERT | (1)將值value插入列表key中,位於pivot前面或者后面 (2)pivot不存在於列表key時,不執行任何操作 (3)key不存在,不執行任何操作 |
LINSERT key BEFORE|AFTER pivot value |
| LLEN | (1)返回列表key的長度 (2)key不存在,返回0 |
LLEN key |
| LTRIM | (1)對一個列表進行修剪,讓列表只返回指定區間內的元素,不存在指定區間內的都將被移除 | LTRIM key start stop |
| RPOP | (1)移除並返回列表key的尾元素 | RPOP key |
| RPOPLPUSH | 在一個原子時間內,執行兩個動作: (1)將列表source中最后一個元素彈出並返回給客戶端 (2)將source彈出的元素插入到列表desination,作為destination列表的頭元素 |
RPOPLPUSH source destination |
| RPUSH | (1)將一個或多個值value插入到列表key的表尾 | RPUSH key value [value ...] |
| RPUSHX | (1)將value插入到列表key的表尾,當且僅當key存在並且是一個列表 (2)key不存在,RPUSHX什么都不做 |
RPUSHX key value |
接着看一下這些命令的實際使用效果:

工具所限,LSET、LINSERT、RPOPLPUSH幾個命令沒法演示,上面演示了其他的基本命令,應該足以理解Redis的List了,操作List千萬注意區分LPUSH、RPUSH兩個命令,把數據添加到表頭和把數據添加到表尾是完全不一樣的兩種結果。
另外List還有BLPOP、BRPOP、BRPOPLPUSH三個命令沒有說,它們是幾個POP的阻塞版本,即沒有數據可以彈出的時候將阻塞客戶端直到超時或者發現有可以彈出的元素為止。
SET數據結構相關操作
接着我們看一下SET數據結構的相關操作:
| 命令 | 描述 | 用法 |
| SADD | (1)將一個或多個member元素加入到key中,已存在在集合的member將被忽略 (2)假如key不存在,則只創建一個只包含member元素做成員的集合 (3)當key不是集合類型時,將返回一個錯誤 |
SADD key number [member ...] |
| SCARD | (1)返回key對應的集合中的元素數量 | SCARD key |
| SDIFF | (1)返回一個集合的全部成員,該集合是第一個Key對應的集合和后面key對應的集合的差集 | SDIFF key [key ...] |
| SDIFFSTORE | (1)和SDIFF類似,但結果保存到destination集合而不是簡單返回結果集 (2) destination如果已存在,則覆蓋 |
SDIFFSTORE destionation key [key ...] |
| SINTER | (1)返回一個集合的全部成員,該集合是所有給定集合的交集 (2)不存在的key被視為空集 |
SINTER key [key ...] |
| SINTERSTORE | (1)和SINTER類似,但結果保存早destination集合而不是簡單返回結果集 (2)如果destination已存在,則覆蓋 (3)destination可以是key本身 |
SINTERSTORE destination key [key ...] |
| SISMEMBER | (1)判斷member元素是否key的成員,0表示不是,1表示是 | SISMEMBER key member |
| SMEMBERS | (1)返回集合key中的所有成員 (2)不存在的key被視為空集 |
SMEMBERS key |
| SMOVE | (1)原子性地將member元素從source集合移動到destination集合 (2)source集合中不包含member元素,SMOVE命令不執行任何操作,僅返回0 (3)destination中已包含member元素,SMOVE命令只是簡單做source集合的member元素移除 |
SMOVE source desination member |
| SPOP | (1)移除並返回集合中的一個隨機元素,如果count不指定那么隨機返回一個隨機元素 (2)count為正數且小於集合元素數量,那么返回一個count個元素的數組且數組中的元素各不相同 (3)count為正數且大於等於集合元素數量,那么返回整個集合 (4)count為負數那么命令返回一個數組,數組中的元素可能重復多次,數量為count的絕對值 |
SPOP key [count] |
| SRANDMEMBER | (1)如果count不指定,那么返回集合中的一個隨機元素 (2)count同上 |
SRANDMEMBER key [count] |
| SREM | (1)移除集合key中的一個或多個member元素,不存在的member將被忽略 | SREM key member [member ...] |
| SUNION | (1)返回一個集合的全部成員,該集合是所有給定集合的並集 (2)不存在的key被視為空集 |
SUNION key [key ...] |
| SUNIONSTORE | (1)類似SUNION,但結果保存到destination集合而不是簡單返回結果集 (2)destination已存在,覆蓋舊值 (3)destination可以是key本身 |
SUNION destination key [key ...] |
同樣,實際測試一下Set:

除了SINTER沒有用到,其他應該比較全面地展示了Set的相關使用。
SortedSet數據結構相關操作
數據結構最后說一下SortedSet相關操作,最近有一個場景需要實現Redis分頁+高效移除數據,一下子沒找到好的數據結構,后來想起了SortedSet才解決了問題,看來積累與儲備還是非常有用的,
SortedSet顧名思義,即有序的Set,看下相關命令:
| 命令 | 描述 | 用法 |
| ZADD | (1)將一個或多個member元素及其score值加入有序集key中 (2)如果member已經是有序集的成員,那么更新member對應的score並重新插入member保證member在正確的位置上 (3)score可以是整數值或雙精度浮點數 |
ZADD key score member [[score member] [score member] ...] |
| ZCARD | (1)返回有序集key的元素個數 | ZCARD key |
| ZCOUNT | (1) 返回有序集key中,score值>=min且<=max的成員的數量 | ZCOUNT key min max |
| ZRANGE | (1)返回有序集key中指定區間內的成員,成員位置按score從小到大排序 (2)具有相同score值的成員按字典序排列 (3)需要成員按score從大到小排列,使用ZREVRANGE命令 (4)下標參數start和stop都以0為底,也可以用負數,-1表示最后一個成員,-2表示倒數第二個成員 (5)可通過WITHSCORES選項讓成員和它的score值一並返回 |
ZRANGE key start stop [WITHSCORES] |
| ZRANK | (1)返回有序集key中成員member的排名,有序集成員按score值從小到大排列 (2)排名以0為底,即score最小的成員排名為0 (3)ZREVRANK命令可將成員按score值從大到小排名 |
ZRANK key number |
| ZREM | (1)移除有序集key中的一個或多個成員,不存在的成員將被忽略 (2)當key存在但不是有序集時,返回錯誤 |
ZREM key member [member ...] |
| ZREMRANGEBYRANK | (1)移除有序集key中指定排名區間內的所有成員 | ZREMRANGEBYRANK key start stop |
| ZREMRANGEBYSCORE | (1)移除有序集key中,所有score值>=min且<=max之間的成員 | ZREMRANGEBYSCORE key min max |
還有若干不是很常用的命令沒有寫,就略過了,有興趣的可以自己看一下,接着看一下SortedSet實際使用:

這個地方排名的時候稍微注意下,和我們認為的排名有些微區別,比如1 1 2 3,由於有兩個1,因此3正序的Rank應當為2(以0為下標),但實際上會是3,所以Rank應當理解為元素在集合中的下標位置更加准確。
Redis的Key相關操作
寫完了Redis的數據結構,接着我們看下Redis的Key相關操作:
| 命令 | 描述 | 用法 |
| DEL | (1)刪除給定的一個或多個key (2)不存在的Key將被忽略 |
DEL key [key ...] |
| EXISTS | (1)檢查給定key是否存在 | EXISTS key |
| EXPIRE | (1)為給定key設置生存時間,key過期時它會被自動刪除 (2)對一個已經指定生存時間的Key設置執行EXPIRE,新的值會代替舊的值 |
EXPIRE key seconds |
| EXPIREAT | (1)同EXPIRE,但此命令指定的是UNIX時間戳,單位為秒 | EXPIRE key timestamp |
| KEYS | (1)查找所有符合給定模式pattern的key,下面舉一下例子 (2)KEYS *匹配所有key (3)KEYS h?llo匹配hello、hallo、hxllo等 (4)KEYS h*llo匹配hllo、heeeeello等 (5)KEYS h[ae]llo匹配hello和hallo (6)特殊符號想當做查找內容經的使用\ |
KEYS pattern |
| MIGRATE |
(1)原子性地將key從當前實例傳送到目標實例指定的數據庫上 (2)原數據庫Key刪除,新數據庫Key增加 (3)阻塞進行遷移的兩個實例,直到遷移成功、遷移失敗、等待超時三個之一發生 |
MIGRATE host port key destination-db timeout [COPY] [REPLACE] |
| MOVE | (1)將當前數據庫的key移動到給定數據庫的db中 (2)執行成功的條件為當前數據庫有key,給定數據庫沒有key |
MOVE key db |
| PERSIST | (1)移除給定key的生存時間,將key變為持久的 | PERSIST key |
| RANDOMKEY | (1)從當前數據庫隨機返回且不刪除一個key, | RANDOMKEY |
| RENAME | (1)將key改名為newkey (2)當key和newkey相同或key不存在,報錯 (3)newkey已存在,RENAME將覆蓋舊值 |
RENAME key newkey |
| TTL | (1)以秒為單位,返回給定的key剩余生存時間 | TTL key |
| PTTL | (1)以毫秒為單位,返回給定的key剩余生存時間 | PTTL key |
| TYPE | (1)返回key鎖存儲的值的類型 | TYPE key |
簡單看一下實際使用:

這里特別注意KEYS命令,雖然KEYS命令速度非常快,但是當Redis中百萬、千萬甚至過億數據的時候,掃描所有Redis的Key,速度仍然會下降,由於Redis是單線程模型,這將導致后面的命令阻塞直到KEYS命令執行完。
因此當Redis中存儲的數據達到了一定量級(經驗值從10W開始就值得注意了)的時候,必須警惕KEYS造成Redis整體性能下降。
系統相關命令
接着介紹一下部分系統相關命令:
| 命令 | 描述 | 用法 |
| BGREWRITEAOF | (1)手動觸發AOF重寫操作,用於減小AOF文件體積 | BGREWRITEAOF |
| BGSAVE | (1)后台異步保存當前數據庫的數據到磁盤 | BGSAVE |
| CLIENT KILL | (1)關閉地址為ip:port的客戶端 (2)由於Redis為單線程設計,因此當當前命令執行完之后才會關閉客戶端 |
CLIENT KILL ip:port |
| CLIENT LIST | (1)以可讀的格式,返回所有連接到服務器的客戶端信息和統計數據 | CLIENT LIST |
| CONFIG GET | (1)取得運行中的Redis服務器配置參數 (2)支持* |
CONFIG GET parameter |
| CONFIG RESETSTAT | (1)重置INFO命令中的某些統計數據,例如Keyspace hits、Keyspace misses等 | CONFIG RESETSTAT |
| CONFIG REWRITE | (1)對啟動Redis時指定的redis.conf文件進行改寫 | CONFIG REWRITE |
| CONFIG SET | (1)動態調整Redis服務器的配置而無需重啟 (2)修改后的配置立即生效 |
CONFIG SET parameter value |
| SELECT | (1)切換到指定數據庫,數據庫索引index用數字指定,以0作為起始索引值 (2)默認使用0號數據庫 |
SELECT index |
| DBSIZE | (1)返回當前數據庫的Key的數量 | DBSIZE |
| DEBUG OBJECT | (1)這是一個調試命令,不應當被客戶端使用 (2)key存在時返回有關信息,key不存在時返回錯誤 |
DEBUG OBJECT key |
| FLUSHALL | (1)清空整個Redis服務器的數據 | FLUSHALL |
| FLUSHDB | (1)清空當前數據庫中的所有數據 | FLUSHDB |
| INFO | (1)以一種易於解釋且易於閱讀的格式,返回Redis服務器的各種信息和統計數值 (2)通過給定可選參數section,可以讓命令只返回某一部分信息 |
INFO [section] |
| LASTSAVE | (1)返回最近一次Redis成功將數據保存到磁盤上的時間,以UNIX時間戳格式表示 | LASTSAVE |
| MONITOR | (1)實時打印出Redis服務器接收到的命令,調試用 | MONITOR |
| SHUTDOWN | (1)停止所有客戶端 (2)如果至少有一個保存點在等待,執行SAVE命令 (3)如果AOF選項被打開,更新AOF文件 (4)關閉Redis服務器 |
SHUTDOWN [SAVE|NOSAVE] |
看下命令的使用演示:

SELECT命令忘了,想起來的時候數據庫已經清空了就算了,使用SELECT后控制台會變成"127.0.0.1:6379[3]>",即帶上數據庫的index。
Redis的事務
最后,本文簡單說一下Redis的事務機制,首先Redis的事務是由DISCARD、EXEC、MULTI、UNWATCH、WATCH五個命令來保證的:
| 命令 | 描述 | 用法 |
| DISCARD | (1)取消事務 (2)如果正在使用WATCH命令監視某個/某些key,那么取消所有監視,等同於執行UNWATCH |
DISCARD |
| EXEC | (1)執行所有事務塊內的命令 (2)如果某個/某些key正處於WATCH命令監視之下且事務塊中有和這個/這些key相關的命令,那么EXEC命令只在這個/這些key沒有被其他命令改動的情況下才會執行並生效,否則該事務被打斷 |
EXEC |
| MULTI | (1)標記一個事務塊的開始 (2)事務塊內的多條命令會按照先后順序被放入一個隊列中,最后由EXEC命令原子性地執行 |
MULTI |
| UNWATCH | (1)取消WATCH命令對所有key的監視 (2)如果WATCH之后,EXEC/DISCARD命令先被執行了,UNWATCH命令就沒必要執行了 |
UNWATCH |
| WATCH | (1)監視一個/多個key,如果在事務執行之前這個/這些key被其他命令改動,那么事務將被打斷 | WATCH key [key ...] |
首先我們看一下事務沒有被打斷的情況:

看到開啟事務之后,所有的命令返回的都是QUEUED,即放入隊列,而不是直接執行。
接着模擬一下事務被打斷的情況,WATCH一下Number這個Key,我另外起了一個Redis客戶端INCR了一下Number,結果為:

看到,並沒有命令被執行,返回nil即事務被打斷。
接着簡單說一下事務,和數據庫類似的,事務保證的是兩點:
- 隔離,所有命令序列化、按順序執行,事務執行過程中不會被其他客戶端發來的命令打斷
- 原子性,事務中的命令要么全部執行,要么全部不執行
另外,Redis的事務並不支持回滾,這個其實網上已經說法挺多了,大致上是兩個原因:
- Redis命令只會因為語法而失敗(且這些問題不能再入隊時被發現),或是命令用在了錯誤類型的鍵上面,也就是說,從實用性角度來說,失敗的命令是由於編程錯誤造成的,而這些錯誤應該在開發的過程中被發現而不應該出現在生產環境中
- Redis內部可以保持簡單且快速,因為不需要對回滾進行支持
總而言之,對Redis來說,回滾無法解決編程錯誤帶來的問題,因此還不如更簡單、更快速地無回滾處理事務。
下期預告
最后預告一下最后一篇文章會寫的內容,四部分:
- Redis線程模型
- Redis的RDB
- Redis的AOF
- Redis的集群方式
喜歡的朋友可以關注一下最后一篇文章。
