一、Nosql概述
1、單機Mysql時代
90年代,一個網站的訪問量一般不會太大,單個數據庫完全夠用。隨着用戶增多,網站出現以下問題:
- 數據量增加到一定程度,單機數據庫就放不下了
- 數據的索引(B+ Tree),一個機器內存也存放不下
- 訪問量變大后(讀寫混合),一台服務器承受不住。

2、Memcached(緩存) + Mysql + 垂直拆分(讀寫分離)
網站80%的情況都是在讀,每次都要去查詢數據庫的話就十分的麻煩!所以說我們希望減輕數據庫的壓力,我們可以使用緩存來保證效率!

優化過程經歷了以下幾個過程:
- 優化數據庫的數據結構和索引(難度大)
- 文件緩存,通過IO流獲取比每次都訪問數據庫效率略高,但是流量爆炸式增長時候,IO流也承受不了
- MemCache,當時最熱門的技術,通過在數據庫和數據庫訪問層之間加上一層緩存,第一次訪問時查詢數據庫,將結果保存到緩存,后續的查詢先檢查緩存,若有直接拿去使用,效率顯著提升。
3、分庫分表 + 水平拆分 + Mysql集群

4、如今最近的年代
如今信息量井噴式增長,各種各樣的數據出現(用戶定位數據,圖片數據等),大數據的背景下關系型數據庫(RDBMS)無法滿足大量數據要求。Nosql數據庫就能輕松解決這些問題。目前一個基本的互聯網項目:

5、為什么要用NoSQL ?
用戶的個人信息,社交網絡,地理位置。用戶自己產生的數據,用戶日志等等爆發式增長!這時候我們就需要使用NoSQL數據庫的,Nosql可以很好的處理以上的情況!
什么是Nosql
NoSQL = Not Only SQL(不僅僅是SQL)
Not Only Structured Query Language
關系型數據庫:列+行,同一個表下數據的結構是一樣的。
非關系型數據庫:數據存儲沒有固定的格式,並且可以進行橫向擴展。
NoSQL泛指非關系型數據庫,隨着web2.0互聯網的誕生,傳統的關系型數據庫很難對付web2.0時代!尤其是超大規模的高並發的社區,暴露出來很多難以克服的問題,NoSQL在當今大數據環境下發展的十分迅速,Redis是發展最快的。
Nosql特點
1.方便擴展(數據之間沒有關系,很好擴展!)
2.大數據量高性能(Redis一秒可以寫8萬次,讀11萬次,NoSQL的緩存記錄級,是一種細粒度的緩存,性能會比較高!)
3.數據類型是多樣型的!(不需要事先設計數據庫,隨取隨用)
4.傳統的 RDBMS 和 NoSQL
傳統的 RDBMS(關系型數據庫)
結構化組織
SQL
數據和關系都存在單獨的表中 row col
操作,數據定義語言
嚴格的一致性
基礎的事務
...Nosql
不僅僅是數據
沒有固定的查詢語言
鍵值對存儲,列存儲,文檔存儲,圖形數據庫(社交關系)
最終一致性
CAP定理和BASE
高性能,高可用,高擴展
...
5.大數據時代的3V :主要是描述問題的
海量Velume
多樣Variety
實時Velocity
6.大數據時代的3高 : 主要是對程序的要求
高並發
高可擴
高性能
真正在公司中的實踐:NoSQL + RDBMS 一起使用才是最強的。
二、Redis入門
Redis是什么?
Redis(Remote Dictionary Server ),即遠程字典服務。
是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日志型、Key-Value數據庫,並提供多種語言的API。
與memcached一樣,為了保證效率,數據都是緩存在內存中。區別的是redis會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了master-slave(主從)同步。
Redis能干什么?
- 內存存儲、持久化,內存是斷電即失的,所以需要持久化(RDB、AOF)
- 高效率、用於高速緩沖
- 發布訂閱系統
- 地圖信息分析
- 計時器、計數器(eg:瀏覽量)
- 。。。
特性
- 多樣的數據類型
- 持久化
- 集群
- 事務
- ...
環境搭建(略)
性能測試
redis-benchmark:Redis官方提供的性能測試工具,參數選項如下:

簡單測試:
# 測試:100個並發連接 100000請求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
結果:

基礎知識
redis默認有16個數據庫

默認使用的第0個;
16個數據庫為:DB 0~DB 15 默認使用DB 0 ,可以使用select n切換到DB n,dbsize可以查看當前數據庫的大小,與key數量相關。
127.0.0.1:6379> config get databases # 命令行查看數據庫數量databases 1) "databases" 2) "16"127.0.0.1:6379> select 8 # 切換數據庫 DB 8
OK
127.0.0.1:6379[8]> dbsize # 查看數據庫大小
(integer) 0不同數據庫之間 數據是不能互通的,並且dbsize 是根據庫中key的個數。
127.0.0.1:6379> set name sakura
OK
127.0.0.1:6379> SELECT 8
OK
127.0.0.1:6379[8]> get name # db8中並不能獲取db0中的鍵值對。
(nil)
127.0.0.1:6379[8]> DBSIZE
(integer) 0
127.0.0.1:6379[8]> SELECT 0
OK
127.0.0.1:6379> keys *
- "counter:rand_int"
- "mylist"
- "name"
- "key:rand_int"
"myset:rand_int"
127.0.0.1:6379> DBSIZE # size和key個數相關
(integer) 5
keys * :查看當前數據庫中所有的key。
flushdb:清空當前數據庫中的鍵值對。
flushall:清空所有數據庫的鍵值對。
Redis是單線程的,Redis是基於內存操作的。
所以Redis的性能瓶頸不是CPU,而是機器內存和網絡帶寬。
那么為什么Redis的速度如此快呢,性能這么高呢?QPS達到10W+
Redis為什么單線程還這么快?
-
誤區1:高性能的服務器一定是多線程的?
-
誤區2:多線程(CPU上下文會切換!)一定比單線程效率高!
核心:Redis是將所有的數據放在內存中的,所以說使用單線程去操作效率就是最高的,多線程(CPU上下文會切換:耗時的操作!),對於內存系統來說,如果沒有上下文切換效率就是最高的,多次讀寫都是在一個CPU上的,在內存存儲數據情況下,單線程就是最佳的方案。
三、五大數據類型
Redis是一個開源(BSD許可),內存存儲的數據結構服務器,可用作數據庫,高速緩存和消息隊列代理。它支持字符串、哈希表、列表、集合、有序集合,位圖,hyperloglogs等數據類型。內置復制、Lua腳本、LRU收回、事務以及不同級別磁盤持久化功能,同時通過Redis Sentinel提供高可用,通過Redis Cluster提供自動分區。
Redis-key
在redis中無論什么數據類型,在數據庫中都是以key-value形式保存,通過進行對Redis-key的操作,來完成對數據庫中數據的操作。
下面學習的命令:
exists key:判斷鍵是否存在del key:刪除鍵值對move key db:將鍵值對移動到指定數據庫expire key second:設置鍵值對的過期時間type key:查看value的數據類型
127.0.0.1:6379> keys * # 查看當前數據庫所有key (empty list or set) 127.0.0.1:6379> set name qinjiang # set key OK 127.0.0.1:6379> set age 20 OK 127.0.0.1:6379> keys * 1) "age" 2) "name" 127.0.0.1:6379> move age 1 # 將鍵值對移動到指定數據庫 (integer) 1 127.0.0.1:6379> EXISTS age # 判斷鍵是否存在 (integer) 0 # 不存在 127.0.0.1:6379> EXISTS name (integer) 1 # 存在 127.0.0.1:6379> SELECT 1 OK 127.0.0.1:6379[1]> keys * 1) "age" 127.0.0.1:6379[1]> del age # 刪除鍵值對 (integer) 1 # 刪除個數127.0.0.1:6379> set age 20
OK
127.0.0.1:6379> EXPIRE age 15 # 設置鍵值對的過期時間(integer) 1 # 設置成功 開始計數
127.0.0.1:6379> ttl age # 查看key的過期剩余時間
(integer) 13
127.0.0.1:6379> ttl age
(integer) 11
127.0.0.1:6379> ttl age
(integer) 9
127.0.0.1:6379> ttl age
(integer) -2 # -2 表示key過期,-1表示key未設置過期時間127.0.0.1:6379> get age # 過期的key 會被自動delete
(nil)
127.0.0.1:6379> keys *
- "name"
127.0.0.1:6379> type name # 查看value的數據類型
string
關於TTL命令
Redis的key,通過TTL命令返回key的過期時間,一般來說有3種:
- 當前key沒有設置過期時間,所以會返回-1.
- 當前key有設置過期時間,而且key已經過期,所以會返回-2.
- 當前key有設置過期時間,且key還沒有過期,故會返回key的正常剩余時間.
關於重命名RENAME和RENAMENX
RENAME key newkey修改 key 的名稱RENAMENX key newkey僅當 newkey 不存在時,將 key 改名為 newkey 。
String(字符串)
普通的set、get直接略過。
常用命令及其示例:
APPEND key value: 向指定的key的value后追加字符串
127.0.0.1:6379> set msg hello
OK
127.0.0.1:6379> append msg " world"
(integer) 11
127.0.0.1:6379> get msg
“hello world”
DECR/INCR key: 將指定key的value數值進行+1/-1(僅對於數字)
127.0.0.1:6379> set age 20
OK
127.0.0.1:6379> incr age
(integer) 21
127.0.0.1:6379> decr age
(integer) 20
INCRBY/DECRBY key n: 按指定的步長對數值進行加減
127.0.0.1:6379> INCRBY age 5
(integer) 25
127.0.0.1:6379> DECRBY age 10
(integer) 15
INCRBYFLOAT key n: 為數值加上浮點型數值
127.0.0.1:6379> INCRBYFLOAT age 5.2
“20.2”
STRLEN key: 獲取key保存值的字符串長度
127.0.0.1:6379> get msg
“hello world”
127.0.0.1:6379> STRLEN msg
(integer) 11
GETRANGE key start end: 按起止位置獲取字符串(閉區間,起止位置都取)
127.0.0.1:6379> get msg
“hello world”
127.0.0.1:6379> GETRANGE msg 3 9
“lo worl”
SETRANGE key offset value:用指定的value 替換key中 offset開始的值
127.0.0.1:6379> set msg hello
OK
127.0.0.1:6379> setrange msg 2 hello
(integer) 7
127.0.0.1:6379> get msg
"hehello"
127.0.0.1:6379> set msg2 world
OK
127.0.0.1:6379> setrange msg2 2 ww
(integer) 5
127.0.0.1:6379> get msg2
"wowwd"
GETSET key value: 將給定 key 的值設為 value ,並返回 key 的舊值(old value)。
127.0.0.1:6379> GETSET msg test
“hello world”
SETNX key value: 僅當key不存在時進行set
127.0.0.1:6379> SETNX msg test
(integer) 0
127.0.0.1:6379> SETNX name sakura
(integer) 1
SETEX key seconds value: set 鍵值對並設置過期時間
127.0.0.1:6379> setex name 10 root
OK
127.0.0.1:6379> get name
(nil)
MSET key1 value1 [key2 value2..]: 批量set鍵值對
127.0.0.1:6379> MSET k1 v1 k2 v2 k3 v3
OK
MSETNX key1 value1 [key2 value2..]: 批量設置鍵值對,僅當參數中所有的key都不存在時執行
127.0.0.1:6379> MSETNX k1 v1 k4 v4
(integer) 0
MGET key1 [key2..]: 批量獲取多個key保存的值
127.0.0.1:6379> MGET k1 k2 k3
1) “v1”
2) “v2”
3) “v3”
PSETEX key milliseconds value: 和 SETEX 命令相似,但它以毫秒為單位設置 key 的生存時間
String類似的使用場景:value除了是字符串還可以是數字,用途舉例:
- 計數器
- 統計多單位的數量:uid:123666:follow 0
- 粉絲數
- 對象存儲緩存
List(列表)
Redis列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)
一個列表最多可以包含 232 - 1 個元素 (4294967295, 每個列表超過40億個元素)。
首先我們列表,可以經過規則定義將其變為隊列、棧、雙端隊列等。

正如圖Redis中List是可以進行雙端操作的,所以命令也就分為了LXXX和RLLL兩類,有時候L也表示List例如LLEN
LPUSH/RPUSH key value1[value2..]從左邊/右邊向列表中PUSH值(一個或者多個)。LRANGE key start end獲取list 起止元素==(索引從左往右 遞增)==LPUSHX/RPUSHX key value向已存在的列名中push值(一個或者多個)LINSERT key BEFORE|AFTER pivot value在指定列表元素的前/后 插入valueLLEN key查看列表長度LINDEX key index通過索引獲取列表元素LSET key index value通過索引為元素設值LPOP/RPOP key從最左邊/最右邊移除值 並返回RPOPLPUSH source destination將列表的尾部(右)最后一個值彈出,並返回,然后加到另一個列表的頭部LTRIM key start end通過下標截取指定范圍內的列表LREM key count valueList中是允許value重復的 count > 0:從頭部開始搜索 然后刪除指定的value 至多刪除count個 count < 0:從尾部開始搜索… count = 0:刪除列表中所有的指定value。BLPOP/BRPOP key1[key2] timout移出並獲取列表的第一個/最后一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素為止。BRPOPLPUSH source destination timeout和RPOPLPUSH功能相同,如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素為止。
代碼示例:
---------------------------LPUSH---RPUSH---LRANGE--------------------------------127.0.0.1:6379> LPUSH mylist k1 # LPUSH mylist=>{1}
(integer) 1
127.0.0.1:6379> LPUSH mylist k2 # LPUSH mylist=>{2,1}
(integer) 2
127.0.0.1:6379> RPUSH mylist k3 # RPUSH mylist=>{2,1,3}
(integer) 3
127.0.0.1:6379> get mylist # 普通的get是無法獲取list值的
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> LRANGE mylist 0 4 # LRANGE 獲取起止位置范圍內的元素
- "k2"
- "k1"
- "k3"
127.0.0.1:6379> LRANGE mylist 0 2- "k2"
- "k1"
- "k3"
127.0.0.1:6379> LRANGE mylist 0 1- "k2"
- "k1"
127.0.0.1:6379> LRANGE mylist 0 -1 # 獲取全部元素- "k2"
- "k1"
- "k3"
---------------------------LPUSHX---RPUSHX-----------------------------------
127.0.0.1:6379> LPUSHX list v1 # list不存在 LPUSHX失敗
(integer) 0
127.0.0.1:6379> LPUSHX list v1 v2
(integer) 0
127.0.0.1:6379> LPUSHX mylist k4 k5 # 向mylist中 左邊 PUSH k4 k5
(integer) 5
127.0.0.1:6379> LRANGE mylist 0 -1
- "k5"
- "k4"
- "k2"
- "k1"
- "k3"
---------------------------LINSERT--LLEN--LINDEX--LSET----------------------------
127.0.0.1:6379> LINSERT mylist after k2 ins_key1 # 在k2元素后 插入ins_key1
(integer) 6
127.0.0.1:6379> LRANGE mylist 0 -1
- "k5"
- "k4"
- "k2"
- "ins_key1"
- "k1"
- "k3"
127.0.0.1:6379> LLEN mylist # 查看mylist的長度
(integer) 6
127.0.0.1:6379> LINDEX mylist 3 # 獲取下標為3的元素
"ins_key1"
127.0.0.1:6379> LINDEX mylist 0
"k5"
127.0.0.1:6379> LSET mylist 3 k6 # 將下標3的元素 set值為k6
OK
127.0.0.1:6379> LRANGE mylist 0 -1- "k5"
- "k4"
- "k2"
- "k6"
- "k1"
- "k3"
---------------------------LPOP--RPOP--------------------------
127.0.0.1:6379> LPOP mylist # 左側(頭部)彈出
"k5"
127.0.0.1:6379> RPOP mylist # 右側(尾部)彈出
"k3"---------------------------RPOPLPUSH--------------------------
127.0.0.1:6379> LRANGE mylist 0 -1
- "k4"
- "k2"
- "k6"
- "k1"
127.0.0.1:6379> RPOPLPUSH mylist newlist # 將mylist的最后一個值(k1)彈出,加入到newlist的頭部
"k1"
127.0.0.1:6379> LRANGE newlist 0 -1- "k1"
127.0.0.1:6379> LRANGE mylist 0 -1- "k4"
- "k2"
- "k6"
---------------------------LTRIM--------------------------
127.0.0.1:6379> LTRIM mylist 0 1 # 截取mylist中的 0~1部分
OK
127.0.0.1:6379> LRANGE mylist 0 -1
- "k4"
- "k2"
初始 mylist: k2,k2,k2,k2,k2,k2,k4,k2,k2,k2,k2
---------------------------LREM--------------------------
127.0.0.1:6379> LREM mylist 3 k2 # 從頭部開始搜索 至多刪除3個 k2
(integer) 3刪除后:mylist: k2,k2,k2,k4,k2,k2,k2,k2
127.0.0.1:6379> LREM mylist -2 k2 #從尾部開始搜索 至多刪除2個 k2
(integer) 2刪除后:mylist: k2,k2,k2,k4,k2,k2
---------------------------BLPOP--BRPOP--------------------------
mylist: k2,k2,k2,k4,k2,k2
newlist: k1127.0.0.1:6379> BLPOP newlist mylist 30 # 從newlist中彈出第一個值,mylist作為候選
- "newlist" # 彈出
- "k1"
127.0.0.1:6379> BLPOP newlist mylist 30- "mylist" # 由於newlist空了 從mylist中彈出
- "k2"
127.0.0.1:6379> BLPOP newlist 30
(30.10s) # 超時了127.0.0.1:6379> BLPOP newlist 30 # 我們連接另一個客戶端向newlist中push了test, 阻塞被解決。
- "newlist"
"test"
(12.54s)
小結
-
list實際上是一個鏈表,before Node after , left, right 都可以插入值
-
如果key不存在,則創建新的鏈表
-
如果key存在,新增內容
-
如果移除了所有值,空鏈表,也代表不存在
-
在兩邊插入或者改動值,效率最高!修改中間元素,效率相對較低
應用:
消息排隊!消息隊列(Lpush Rpop),棧(Lpush Lpop)
Set(集合)
Redis的Set是string類型的無序集合。集合成員是唯一的,這就意味着集合中不能出現重復的數據。
Redis中集合是通過哈希表實現的,所以添加,刪除,查找的復雜度都是O(1)。
集合中最大的成員數為 232 - 1 (4294967295, 每個集合可存儲40多億個成員)。
SADD key member1[member2..]向集合中無序增加一個/多個成員SCARD key獲取集合的成員數SMEMBERS key返回集合中所有的成員SISMEMBER key member查詢member元素是否是集合的成員,結果是無序的SRANDMEMBER key [count]隨機返回集合中count個成員,count缺省值為1SPOP key [count]隨機移除並返回集合中count個成員,count缺省值為1SMOVE source destination member將source集合的成員member移動到destination集合SREM key member1[member2..]移除集合中一個/多個成員SDIFF key1[key2..]返回所有集合的差集 key1- key2 - …SDIFFSTORE destination key1[key2..]在SDIFF的基礎上,將結果保存到集合中==(覆蓋)==。不能保存到其他類型key噢!SINTER key1 [key2..]返回所有集合的交集SINTERSTORE destination key1[key2..]在SINTER的基礎上,存儲結果到集合中。覆蓋SUNION key1 [key2..]返回所有集合的並集SUNIONSTORE destination key1 [key2..]在SUNION的基礎上,存儲結果到及和張。覆蓋SSCAN KEY [MATCH pattern] [COUNT count]在大量數據環境下,使用此命令遍歷集合中元素,每次遍歷部分
代碼示例
---------------SADD--SCARD--SMEMBERS--SISMEMBER--------------------127.0.0.1:6379> SADD myset m1 m2 m3 m4 # 向myset中增加成員 m1~m4
(integer) 4
127.0.0.1:6379> SCARD myset # 獲取集合的成員數目
(integer) 4
127.0.0.1:6379> smembers myset # 獲取集合中所有成員
- "m4"
- "m3"
- "m2"
- "m1"
127.0.0.1:6379> SISMEMBER myset m5 # 查詢m5是否是myset的成員
(integer) 0 # 不是,返回0
127.0.0.1:6379> SISMEMBER myset m2
(integer) 1 # 是,返回1
127.0.0.1:6379> SISMEMBER myset m3
(integer) 1---------------------SRANDMEMBER--SPOP----------------------------------
127.0.0.1:6379> SRANDMEMBER myset 3 # 隨機返回3個成員
- "m2"
- "m3"
- "m4"
127.0.0.1:6379> SRANDMEMBER myset # 隨機返回1個成員
"m3"
127.0.0.1:6379> SPOP myset 2 # 隨機移除並返回2個成員- "m1"
- "m4"
將set還原到{m1,m2,m3,m4}
---------------------SMOVE--SREM----------------------------------------
127.0.0.1:6379> SMOVE myset newset m3 # 將myset中m3成員移動到newset集合
(integer) 1
127.0.0.1:6379> SMEMBERS myset
- "m4"
- "m2"
- "m1"
127.0.0.1:6379> SMEMBERS newset- "m3"
127.0.0.1:6379> SREM newset m3 # 從newset中移除m3元素
(integer) 1
127.0.0.1:6379> SMEMBERS newset
(empty list or set)下面開始是多集合操作,多集合操作中若只有一個參數默認和自身進行運算
setx=>{m1,m2,m4,m6}, sety=>{m2,m5,m6}, setz=>{m1,m3,m6}
-----------------------------SDIFF------------------------------------
127.0.0.1:6379> SDIFF setx sety setz # 等價於setx-sety-setz
- "m4"
127.0.0.1:6379> SDIFF setx sety # setx - sety- "m4"
- "m1"
127.0.0.1:6379> SDIFF sety setx # sety - setx- "m5"
-------------------------SINTER---------------------------------------
共同關注(交集)
127.0.0.1:6379> SINTER setx sety setz # 求 setx、sety、setx的交集
- "m6"
127.0.0.1:6379> SINTER setx sety # 求setx sety的交集- "m2"
- "m6"
-------------------------SUNION---------------------------------------
127.0.0.1:6379> SUNION setx sety setz # setx sety setz的並集
- "m4"
- "m6"
- "m3"
- "m2"
- "m1"
- "m5"
127.0.0.1:6379> SUNION setx sety # setx sety 並集- "m4"
- "m6"
- "m2"
- "m1"
"m5"
Hash(哈希)
Redis hash 是一個string類型的field和value的映射表,hash特別適合用於存儲對象。
Set就是一種簡化的Hash,只變動key,而value使用默認值填充。可以將一個Hash表作為一個對象進行存儲,表中存放對象的信息。
HSET key field value將哈希表 key 中的字段 field 的值設為 value 。重復設置同一個field會覆蓋,返回0HMSET key field1 value1 [field2 value2..]同時將多個 field-value (域-值)對設置到哈希表 key 中。HSETNX key field value只有在字段 field 不存在時,設置哈希表字段的值。HEXISTS key field查看哈希表 key 中,指定的字段是否存在。HGET key field value獲取存儲在哈希表中指定字段的值HMGET key field1 [field2..]獲取所有給定字段的值HGETALL key獲取在哈希表key 的所有字段和值HKEYS key獲取哈希表key中所有的字段HLEN key獲取哈希表中字段的數量HVALS key獲取哈希表中所有值HDEL key field1 [field2..]刪除哈希表key中一個/多個field字段HINCRBY key field n為哈希表 key 中的指定字段的整數值加上增量n,並返回增量后結果 一樣只適用於整數型字段HINCRBYFLOAT key field n為哈希表 key 中的指定字段的浮點數值加上增量 n。HSCAN key cursor [MATCH pattern] [COUNT count]迭代哈希表中的鍵值對。
代碼示例
------------------------HSET--HMSET--HSETNX---------------- 127.0.0.1:6379> HSET studentx name sakura # 將studentx哈希表作為一個對象,設置name為sakura (integer) 1 127.0.0.1:6379> HSET studentx name gyc # 重復設置field進行覆蓋,並返回0 (integer) 0 127.0.0.1:6379> HSET studentx age 20 # 設置studentx的age為20 (integer) 1 127.0.0.1:6379> HMSET studentx sex 1 tel 15623667886 # 設置sex為1,tel為15623667886 OK 127.0.0.1:6379> HSETNX studentx name gyc # HSETNX 設置已存在的field (integer) 0 # 失敗 127.0.0.1:6379> HSETNX studentx email 12345@qq.com (integer) 1 # 成功----------------------HEXISTS--------------------------------
127.0.0.1:6379> HEXISTS studentx name # name字段在studentx中是否存在
(integer) 1 # 存在
127.0.0.1:6379> HEXISTS studentx addr
(integer) 0 # 不存在-------------------HGET--HMGET--HGETALL-----------
127.0.0.1:6379> HGET studentx name # 獲取studentx中name字段的value
"gyc"
127.0.0.1:6379> HMGET studentx name age tel # 獲取studentx中name、age、tel字段的value
- "gyc"
- "20"
- "15623667886"
127.0.0.1:6379> HGETALL studentx # 獲取studentx中所有的field及其value- "name"
- "gyc"
- "age"
- "20"
- "sex"
- "1"
- "tel"
- "15623667886"
- "email"
- "12345@qq.com"
--------------------HKEYS--HLEN--HVALS--------------
127.0.0.1:6379> HKEYS studentx # 查看studentx中所有的field
- "name"
- "age"
- "sex"
- "tel"
- "email"
127.0.0.1:6379> HLEN studentx # 查看studentx中的字段數量
(integer) 5
127.0.0.1:6379> HVALS studentx # 查看studentx中所有的value- "gyc"
- "20"
- "1"
- "15623667886"
- "12345@qq.com"
-------------------------HDEL--------------------------
127.0.0.1:6379> HDEL studentx sex tel # 刪除studentx 中的sex、tel字段
(integer) 2
127.0.0.1:6379> HKEYS studentx
- "name"
- "age"
- "email"
-------------HINCRBY--HINCRBYFLOAT------------------------
127.0.0.1:6379> HINCRBY studentx age 1 # studentx的age字段數值+1
(integer) 21
127.0.0.1:6379> HINCRBY studentx name 1 # 非整數字型字段不可用
(error) ERR hash value is not an integer
127.0.0.1:6379> HINCRBYFLOAT studentx weight 0.6 # weight字段增加0.6
"90.8"
Hash變更的數據user name age,尤其是用戶信息之類的,經常變動的信息!Hash更適合於對象的存儲,Sring更加適合字符串存儲!
Zset(有序集合)
不同的是每個元素都會關聯一個double類型的分數(score)。redis正是通過分數來為集合中的成員進行從小到大的排序。
score相同:按字典順序排序
有序集合的成員是唯一的,但分數(score)卻可以重復。
ZADD key score member1 [score2 member2]向有序集合添加一個或多個成員,或者更新已存在成員的分數ZCARD key獲取有序集合的成員數ZCOUNT key min max計算在有序集合中指定區間score的成員數ZINCRBY key n member有序集合中對指定成員的分數加上增量 nZSCORE key member返回有序集中,成員的分數值ZRANK key member返回有序集合中指定成員的索引ZRANGE key start end通過索引區間返回有序集合成指定區間內的成員ZRANGEBYLEX key min max通過字典區間返回有序集合的成員ZRANGEBYSCORE key min max通過分數返回有序集合指定區間內的成員==-inf 和 +inf分別表示最小最大值,只支持開區間()==ZLEXCOUNT key min max在有序集合中計算指定字典區間內成員數量ZREM key member1 [member2..]移除有序集合中一個/多個成員ZREMRANGEBYLEX key min max移除有序集合中給定的字典區間的所有成員ZREMRANGEBYRANK key start stop移除有序集合中給定的排名區間的所有成員ZREMRANGEBYSCORE key min max移除有序集合中給定的分數區間的所有成員ZREVRANGE key start end返回有序集中指定區間內的成員,通過索引,分數從高到底ZREVRANGEBYSCORRE key max min返回有序集中指定分數區間內的成員,分數從高到低排序ZREVRANGEBYLEX key max min返回有序集中指定字典區間內的成員,按字典順序倒序ZREVRANK key member返回有序集合中指定成員的排名,有序集成員按分數值遞減(從大到小)排序ZINTERSTORE destination numkeys key1 [key2 ..]計算給定的一個或多個有序集的交集並將結果集存儲在新的有序集合 key 中,numkeys:表示參與運算的集合數,將score相加作為結果的scoreZUNIONSTORE destination numkeys key1 [key2..]計算給定的一個或多個有序集的交集並將結果集存儲在新的有序集合 key 中ZSCAN key cursor [MATCH pattern\] [COUNT count]迭代有序集合中的元素(包括元素成員和元素分值)
代碼示例
-------------------ZADD--ZCARD--ZCOUNT-------------- 127.0.0.1:6379> ZADD myzset 1 m1 2 m2 3 m3 # 向有序集合myzset中添加成員m1 score=1 以及成員m2 score=2.. (integer) 2 127.0.0.1:6379> ZCARD myzset # 獲取有序集合的成員數 (integer) 2 127.0.0.1:6379> ZCOUNT myzset 0 1 # 獲取score在 [0,1]區間的成員數量 (integer) 1 127.0.0.1:6379> ZCOUNT myzset 0 2 (integer) 2----------------ZINCRBY--ZSCORE--------------------------
127.0.0.1:6379> ZINCRBY myzset 5 m2 # 將成員m2的score +5
"7"
127.0.0.1:6379> ZSCORE myzset m1 # 獲取成員m1的score
"1"
127.0.0.1:6379> ZSCORE myzset m2
"7"--------------ZRANK--ZRANGE-----------------------------------
127.0.0.1:6379> ZRANK myzset m1 # 獲取成員m1的索引,索引按照score排序,score相同索引值按字典順序順序增加
(integer) 0
127.0.0.1:6379> ZRANK myzset m2
(integer) 2
127.0.0.1:6379> ZRANGE myzset 0 1 # 獲取索引在 0~1的成員
- "m1"
- "m3"
127.0.0.1:6379> ZRANGE myzset 0 -1 # 獲取全部成員- "m1"
- "m3"
- "m2"
testset=>{abc,add,amaze,apple,back,java,redis} score均為0
------------------ZRANGEBYLEX---------------------------------
127.0.0.1:6379> ZRANGEBYLEX testset - + # 返回所有成員
- "abc"
- "add"
- "amaze"
- "apple"
- "back"
- "java"
- "redis"
127.0.0.1:6379> ZRANGEBYLEX testset - + LIMIT 0 3 # 分頁 按索引顯示查詢結果的 0,1,2條記錄- "abc"
- "add"
- "amaze"
127.0.0.1:6379> ZRANGEBYLEX testset - + LIMIT 3 3 # 顯示 3,4,5條記錄- "apple"
- "back"
- "java"
127.0.0.1:6379> ZRANGEBYLEX testset (- [apple # 顯示 (-,apple] 區間內的成員- "abc"
- "add"
- "amaze"
- "apple"
127.0.0.1:6379> ZRANGEBYLEX testset [apple [java # 顯示 [apple,java]字典區間的成員- "apple"
- "back"
- "java"
-----------------------ZRANGEBYSCORE---------------------
127.0.0.1:6379> ZRANGEBYSCORE myzset 1 10 # 返回score在 [1,10]之間的的成員
- "m1"
- "m3"
- "m2"
127.0.0.1:6379> ZRANGEBYSCORE myzset 1 5- "m1"
- "m3"
--------------------ZLEXCOUNT-----------------------------
127.0.0.1:6379> ZLEXCOUNT testset - +
(integer) 7
127.0.0.1:6379> ZLEXCOUNT testset [apple [java
(integer) 3------------------ZREM--ZREMRANGEBYLEX--ZREMRANGBYRANK--ZREMRANGEBYSCORE--------------------------------
127.0.0.1:6379> ZREM testset abc # 移除成員abc
(integer) 1
127.0.0.1:6379> ZREMRANGEBYLEX testset [apple [java # 移除字典區間[apple,java]中的所有成員
(integer) 3
127.0.0.1:6379> ZREMRANGEBYRANK testset 0 1 # 移除排名0~1的所有成員
(integer) 2
127.0.0.1:6379> ZREMRANGEBYSCORE myzset 0 3 # 移除score在 [0,3]的成員
(integer) 2testset=> {abc,add,apple,amaze,back,java,redis} score均為0
myzset=> {(m1,1),(m2,2),(m3,3),(m4,4),(m7,7),(m9,9)}
----------------ZREVRANGE--ZREVRANGEBYSCORE--ZREVRANGEBYLEX-----------
127.0.0.1:6379> ZREVRANGE myzset 0 3 # 按score遞減排序,然后按索引,返回結果的 0~3
- "m9"
- "m7"
- "m4"
- "m3"
127.0.0.1:6379> ZREVRANGE myzset 2 4 # 返回排序結果的 索引的2~4- "m4"
- "m3"
- "m2"
127.0.0.1:6379> ZREVRANGEBYSCORE myzset 6 2 # 按score遞減順序 返回集合中分數在[2,6]之間的成員- "m4"
- "m3"
- "m2"
127.0.0.1:6379> ZREVRANGEBYLEX testset [java (add # 按字典倒序 返回集合中(add,java]字典區間的成員- "java"
- "back"
- "apple"
- "amaze"
-------------------------ZREVRANK------------------------------
127.0.0.1:6379> ZREVRANK myzset m7 # 按score遞減順序,返回成員m7索引
(integer) 1
127.0.0.1:6379> ZREVRANK myzset m2
(integer) 4mathscore=>{(xm,90),(xh,95),(xg,87)} 小明、小紅、小剛的數學成績
enscore=>{(xm,70),(xh,93),(xg,90)} 小明、小紅、小剛的英語成績
-------------------ZINTERSTORE--ZUNIONSTORE-----------------------------------
127.0.0.1:6379> ZINTERSTORE sumscore 2 mathscore enscore # 將mathscore enscore進行合並 結果存放到sumscore
(integer) 3
127.0.0.1:6379> ZRANGE sumscore 0 -1 withscores # 合並后的score是之前集合中所有score的和
- "xm"
- "160"
- "xg"
- "177"
- "xh"
- "188"
127.0.0.1:6379> ZUNIONSTORE lowestscore 2 mathscore enscore AGGREGATE MIN # 取兩個集合的成員score最小值作為結果的
(integer) 3
127.0.0.1:6379> ZRANGE lowestscore 0 -1 withscores
- "xm"
- "70"
- "xg"
- "87"
- "xh"
"93"
應用案例:
- set排序 存儲班級成績表 工資表排序!
- 普通消息,1.重要消息 2.帶權重進行判斷
- 排行榜應用實現,取Top N測試
