navicat 連線 mysql 報1251錯誤
redis五種常用的資料結構為string (字串)、list (列表)、set (集合)、hash (雜湊) 和 zset (有序集合)。小白易讀,建議收藏。
萬丈高樓平地起
reids是鍵值對結構的NoSql資料庫,key
都是字串,常說的資料型別不同,說的都是value
。
redis所有的資料都會有一個dicEntry
,眾多dicEntry
組成一個連結串列。上方那個sds
就是key
,可以看出是一個字串。下方那個綠色的redisObject
就是value
。可以看出圖中給的例子就是string
型別。redisObject
會指向真實的資料(比如圖中的字串“world”)。後面我們說的資料型別特指value
string (字串)
Redis 的字串是動態字串,是可以修改的字串。當字串長度小於 1M 時,擴容都是加倍現有的空間,如果超過 1M,擴容時一次只會多擴 1M 的空間。一個字串最大可以承受512M。
常用指令
設定獲取值
127.0.0.1:6379> set name pjjlt
OK
127.0.0.1:6379> get name
"pjjlt"
127.0.0.1:6379> exists name
(integer) 1
設定使用set
,獲取使用get
,檢視某key是否存在用exists
。
設定過期時間
127.0.0.1:6379> setex company 10 gongsi OK 127.0.0.1:6379> get company "gongsi" 127.0.0.1:6379> get company (nil)
可以在設定值的時候直接指定,keycompany
可以存活10秒。此外,也可以將設定值和設定過期時間分開,使用expire
。
127.0.0.1:6379> set company gongsi
OK
127.0.0.1:6379> expire company 10
(integer) 1
127.0.0.1:6379> get company
"gongsi"
127.0.0.1:6379> get company
(nil)
保證不覆蓋value
redis還提供了命令,在設定值的時候,如果發現key
已存在,此次設定失敗,保證原始value
不被覆蓋。使用setnx
命令。
127.0.0.1:6379> setnx company gongsi (integer) 1 # 可以看到第二次設定失敗,返回值為 0. 127.0.0.1:6379> setnx company haha (integer) 0 127.0.0.1:6379> get company "gongsi"
批量設定獲取值
127.0.0.1:6379> mset name pjjlt age 26 company gongsi
OK
127.0.0.1:6379> mget name age company
1) "pjjlt"
2) "26"
3) "gongsi"
批量設定使用mset
,批量獲取使用mget
。批量設定獲取,減少IO,提高效能,你值得擁有。
計數
redis還可以通過自增的方式計數。
127.0.0.1:6379> set key 10
OK
127.0.0.1:6379> incr key
(integer) 11
127.0.0.1:6379> incr key
(integer) 12
# 字串報錯
127.0.0.1:6379> set key2 haha
OK
127.0.0.1:6379> incr key2
(error) ERR value is not an integer or out of range
# 超出long的範圍
127.0.0.1:6379> set key3 9223372036854775807
OK
127.0.0.1:6379> incr key3
(error) ERR increment or decrement would overflow
# key4不存在
127.0.0.1:6379> incr key4
(integer) 1
127.0.0.1:6379> incr key4
(integer) 2
可以通過incr
關鍵字自增,可以看出key自增了兩次。不能給字串自增,那樣會報錯,例如key2。不能超過long
的範圍,那樣也會報錯,例如key3。如果初始key不存在,則增從0開始,例如key4。
追加值
127.0.0.1:6379> set name pj
OK
127.0.0.1:6379> append name jlt
(integer) 5
127.0.0.1:6379> get name
"pjjlt"
字串長度
127.0.0.1:6379> get name
"pjjlt"
127.0.0.1:6379> strlen name
(integer) 5
設定並返回原先值
127.0.0.1:6379> get name
"pjjlt"
127.0.0.1:6379> getset name mj
"pjjlt"
127.0.0.1:6379> get name
"mj"
設定指定位置的字元
127.0.0.1:6379> get name
"mj"
127.0.0.1:6379> setrange name 0 p
(integer) 2
127.0.0.1:6379> get name
"pj"
獲取部分字串
127.0.0.1:6379> set name pjjlt
OK
127.0.0.1:6379> getrange name 0 2
"pjj"
總結
命令 | 解釋 |
---|---|
set | 設定值 |
get | 獲取值 |
setex | 設定值並新增過期時間 |
setnx | 保證不覆蓋value |
mset | 批量設定值 |
mget | 批量獲取值 |
incr | 計數 |
append | 追加值 |
strlen | 字串長度 |
getset | 設定並返回原先值 |
setrange | 設定指定位置的字元 |
getrange | 獲取部分字串 |
內部編碼
雖然某種資料型別的value
名稱是一致的,比如都是string
,但是根據資料量的大小,會採用不同的內部編碼,這樣可以更高效的利用空間嘛。內部編碼型別也儲存在redisObject
中。利用object encoding key
可檢視內部編碼型別。
int
:長整型,超越長整型或者是字串會升級。
embstr
:小於等於44個位元組的字串。筆者用的是redis5.0.9,有人說這個位元組範圍是39,親測是44。查了一下,原始碼確實改了,現在是44.
raw
:大於44個位元組的字串。
127.0.0.1:6379> set name 1234567890
OK
127.0.0.1:6379> object encoding name
"int"
# 這裡設定44個字元
127.0.0.1:6379> set name qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwer
OK
127.0.0.1:6379> object encoding name
"embstr"
# 這裡設定45個字元
127.0.0.1:6379> set name qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwert
OK
127.0.0.1:6379> object encoding name
"raw"
使用場景
可以用於計數
,比如網站訪問量。
可以共享Session
,比如分散式系統,多個例項驗證使用者是否登入。
可以限速
,比如控制一個ip或者一個使用者一定時間內訪問次數。
list (列表)
Redis 的列表相當於 Java 語言裡面的 LinkedList,注意它是連結串列而不是陣列。這意味著list 的插入和刪除操作非常快,時間複雜度為 O(1),但是索引定位很慢,時間複雜度為O(n)。list的兩端都可以彈入彈出資料,所以可以做棧
和佇列
。
棧與佇列
棧
棧如同一個死衚衕,只有一個出口,後進來的先出,先進來的後出。
127.0.0.1:6379> rpush books python java golong
(integer) 3
127.0.0.1:6379> rpop books
"golong"
127.0.0.1:6379> rpop books
"java"
127.0.0.1:6379> rpop books
"python"
127.0.0.1:6379> rpop books
(nil)
資料從右邊進(rpush),右邊出(rpop),先進去的最後出來。
佇列
佇列如同排隊打飯的同學們,先進先出。
127.0.0.1:6379> rpush books python java golong
(integer) 3
127.0.0.1:6379> lpop books
"python"
127.0.0.1:6379> lpop books
"java"
127.0.0.1:6379> lpop books
"golong"
127.0.0.1:6379> lpop books
(nil)
資料從右邊進(rpush),左邊出(lpop),先進先出。
常用命令
向佇列任意位置加入元素
剛才演示的rpush
、lpush
都是從兩頭加入元素,這兩個命令不再演示。還可以使用linsert
在某指定元素前或後插入新的元素。
127.0.0.1:6379> rpush books python java golong
(integer) 3
# 在java前面插入 ruby
127.0.0.1:6379> linsert books before java ruby
(integer) 4
# 在java後面插入 c#
127.0.0.1:6379> linsert books after java c#
(integer) 5
# 檢視所有元素
127.0.0.1:6379> lrange books 0 -1
1) "python"
2) "ruby"
3) "java"
4) "c#"
5) "golong"
根據上面在java
前後插入了ruby
和c#
查詢元素
127.0.0.1:6379> lrange books 0 -1
1) "python"
2) "ruby"
3) "java"
4) "c#"
5) "golong"
127.0.0.1:6379> lindex books 2
"java"
127.0.0.1:6379> llen books
(integer) 5
指令簡單,索性寫一塊吧。
lrange
可以遍歷列表,引數為start
,end
。這裡0 -1,是指從第一個到最後一個,即遍歷列表。
lindex
查詢指定位置的元素,引數是下標值。這個命令是慢查詢,需要遍歷連結串列。
llen
可以檢視列表元素個數。
刪除資料
剛才演示的rpop
、lpop
可以彈出一個元素,不再演示。
可以使用lrem 刪除多個同一元素
count > 0:從左到右,刪除最多 count 個元素。
count < 0:從右到左,刪除最多 count 絕對值 個元素。
count = 0,刪除所有。
# 從左刪除a元素,刪除了3個
127.0.0.1:6379> rpush char a a b b a a c
(integer) 7
127.0.0.1:6379> lrem chae 3 a
(integer) 0
127.0.0.1:6379> lrem char 3 a
(integer) 3
127.0.0.1:6379> lrange char 0 -1
1) "b"
2) "b"
3) "a"
4) "c"
# 從右刪除 3 個a元素
127.0.0.1:6379> rpush char1 a a b b a a c
(integer) 7
127.0.0.1:6379> lrem char1 -3 a
(integer) 3
127.0.0.1:6379> lrange char1 0 -1
1) "a"
2) "b"
3) "b"
4) "c"
# 刪除所有 a 元素
127.0.0.1:6379> rpush char2 a a b b a a c
(integer) 7
127.0.0.1:6379> lrem char2 0 a
(integer) 4
127.0.0.1:6379> lrange char2 0 -1
1) "b"
2) "b"
3) "c"
還可以使用ltrim
擷取一部分資料,刪除其餘資料
127.0.0.1:6379> rpush char3 a b c d e f g
(integer) 7
127.0.0.1:6379> ltrim char3 1 3
OK
127.0.0.1:6379> lrange char3 0 -1
1) "b"
2) "c"
3) "d"
修改
127.0.0.1:6379> lrange books 0 -1
1) "python"
2) "ruby"
3) "java"
4) "c#"
5) "golong"
127.0.0.1:6379> lset books 2 javaScript
OK
127.0.0.1:6379> lrange books 0 -1
1) "python"
2) "ruby"
3) "javaScript"
4) "c#"
5) "golong"
可以用lset
更改某個位置上的元素,這也是個慢查詢,時間複雜度為O(n)。
阻塞操作
blpop
和brpop
在lpop
和rpop
基礎上增加了阻塞時間,如果直接獲取,發現列表中沒有資料,那麼會阻塞等待一段時間,如果該段時間內還是無法得到資料,就返回等待時長。若設定的時間是0
的話,即為無限等待。這裡需要兩個終端做配合。
# 終端1
127.0.0.1:6379> lpop books
(nil)
127.0.0.1:6379> blpop books 5
(nil)
(5.06s)
# 這裡需要在終端1 執行blpop後插入一條資料
127.0.0.1:6379> blpop books 20
1) "books"
2) "java"
(4.61s)
# 這裡需要在終端1 執行blpop後插入一條資料
127.0.0.1:6379> blpop books 0
1) "books"
2) "python"
(9.66s)
# 除此之外,還可以同時阻塞多個佇列,先有資料的那個彈出
127.0.0.1:6379> blpop books schools 0
1) "schools"
2) "hzsy"
(26.75s)
總結
命令 | 解釋 |
---|---|
rpush lpush | 彈入資料 |
rpop lpop | 彈出資料 |
brpop blpop | 阻塞彈出資料 |
linsert | 向佇列任意位置加入元素 |
lrange | 遍歷列表 |
lindex | 查詢指定位置上元素 |
llen | 列表長度 |
lrem | 刪除多個同一元素 |
ltrim | 擷取指定列表 |
lset | 修改列表指定位置元素 |
內部編碼
ziplist
:當列表的元素個數小於list-max-ziplist-entries
配置(預設 512 個),同時列表中每個元素的值都小於list-max-ziplist-value
配置時(預設 64 位元組),Redis 會選用ziplist
來作為 列表 的內部實現來減少記憶體的使用。
linkedlist
:當列表型別無法滿足ziplist
的條件時,Redis會使用linkedlist
作為列表的內部實現。
使用場景
可以做棧
或者佇列
。
還可以利用阻塞功能做訊息佇列
。
hash (雜湊)
Redis 的字典相當於Java語言裡面的HashMap,它是無序字典。內部實現結構上同Java的HashMap也是一致的,同樣的陣列 + 連結串列二維結構。擴容rehash
的時候,採用漸進式。在rehash
時,保留兩個新舊hash結構,查詢的時候都查,再根據定時任務,一點點將舊hash上的資料遷移到新的hash上,遷移完畢,舊hash被刪除,並收回記憶體。我們預設key為hashKey
,filed為小key
。
常用命令
設定值
127.0.0.1:6379> hset user name pjjlt
(integer) 1
127.0.0.1:6379> hset user age 26
(integer) 1
127.0.0.1:6379> hset user company gongsi
(integer) 1
獲取值
127.0.0.1:6379> hget user name
"pjjlt"
刪除field
127.0.0.1:6379> hdel user company
(integer) 1
計算field個數
127.0.0.1:6379> hlen user
(integer) 2
批量設定獲取值
127.0.0.1:6379> hmset user name pjjlt age 26 city shijiazhuang
OK
127.0.0.1:6379> hmget user name age
1) "pjjlt"
2) "26"
判斷filed是否存在
127.0.0.1:6379> hexists user name
(integer) 1
獲取所有filed或者value
127.0.0.1:6379> hkeys user
1) "name"
2) "age"
3) "city"
127.0.0.1:6379> hvals user
1) "pjjlt"
2) "26"
獲取所有filed和value
127.0.0.1:6379> hgetall user
1) "name"
2) "pjjlt"
3) "age"
4) "26"
5) "city"
6) "shijiazhuang"
自增
127.0.0.1:6379> hincrby user age -8
(integer) 18
127.0.0.1:6379> hset user scroe 99.6
(integer) 1
127.0.0.1:6379> hincrbyfloat user scroe 0.4
"100"
hincrby
和hincrbyfloat
分別增加或者減少整型與浮點型。
計算值的長度
127.0.0.1:6379> hget user name
"pjjlt"
127.0.0.1:6379> hstrlen user name
(integer) 5
總結
命令 | 解釋 |
---|---|
hset | 設定值 |
hget | 獲取值 |
hdel | 刪除值 |
hlen | 計算field個數 |
hmset | 批量設定值 |
hmget | 批量獲取值 |
hexists | 判斷field是否存在 |
hkeys | 獲取所有field |
hvals | 獲取所有value |
hgetall | 獲取所有filed和value |
hincrby | 增加整型數值 |
hincrbyfloat | 增加浮點型數值 |
hstrlen | 計算值的長度 |
內部編碼
ziplist
:當列表的元素個數小於list-max-ziplist-entries
配置(預設 512 個),同時列表中每個元素的值都小於list-max-ziplist-value
配置時(預設 64 位元組),Redis 會選用ziplist
來作為 列表 的內部實現來減少記憶體的使用。
hashtable:當雜湊型別無法滿足ziplist
的條件時,Redis會使用hashtable
作為雜湊的內部實現,因為此時ziplist
的讀寫效率會下降,而hashtable
的讀寫時間複雜度為O(1)。
使用場景
hash
很適合快取物件,比如商城系統可以存放商品,hash
key為商品id,field
為各種屬性,value
為資料。當然string
也可以存放商品,只不過它的value
,時json串,還需要解析,從程式碼角度和網路代價來講都不如hash
。
set (集合)
set
相當於Java語言裡面的 HashSet,它內部的鍵值對是無序的唯一的。它的內部實現相當於一個特殊的字典,字典中所有的value
都是一個值NULL。
常用命令
增加元素
127.0.0.1:6379> sadd books java python python ruby java
(integer) 3
sadd
可以新增一個或者多個元素,並且去重。
刪除元素
127.0.0.1:6379> srem books python ruby
(integer) 2
srem
可以刪除一個或者多個元素。
計算元素個數
127.0.0.1:6379> sadd books python ruby c#
(integer) 3
127.0.0.1:6379> scard books
(integer) 4
判斷元素是否在集合中
127.0.0.1:6379> sismember books java
(integer) 1
127.0.0.1:6379> sismember books c
(integer) 0
隨機返回一定數量的元素
127.0.0.1:6379> srandmember books 2
1) "java"
2) "ruby"
127.0.0.1:6379> srandmember books 2
1) "c#"
2) "ruby"
隨機彈出一個元素
127.0.0.1:6379> spop books
"ruby"
127.0.0.1:6379> scard books
(integer) 3
獲取所有元素
127.0.0.1:6379> smembers books
1) "c#"
2) "java"
3) "python"
計算並查集
127.0.0.1:6379> sadd set1 a b c d e
(integer) 5
127.0.0.1:6379> sadd set2 d e f g
(integer) 4
# 計算兩個集合交集
127.0.0.1:6379> sinter set1 set2
1) "e"
2) "d"
# 計算兩個集合並集
127.0.0.1:6379> sunion set1 set2
1) "g"
2) "a"
3) "d"
4) "e"
5) "c"
6) "f"
7) "b"
# 計算兩個集合差集
127.0.0.1:6379> sdiff set1 set2
1) "c"
2) "b"
3) "a"
總結
命令 | 解釋 |
---|---|
sadd | 增加元素 |
srem | 刪除元素 |
scard | 計算元素個數 |
sismember | 判斷元素是否在集合中 |
srandmember | 隨機返回一定數量的元素 |
spop | 隨機彈出一個元素 |
smembers | 獲取所有元素 |
sinter | 計算兩個集合交集 |
sunion | 計算兩個集合並集 |
sdiff | 計算兩個集合差集 |
內部編碼
intset
:當集合中的元素都是整數且元素個數小於set-max-intset-entries
配置(預設 512 個)時,Redis會選用intset
來作為集合的內部實現,從而減少記憶體的使用。
hashtable
:當集合型別無法滿足intset
的條件時,Redis會使用hashtable
作為集合的內部實現。
使用場景
利用並查集
可以用於查詢使用者共同愛好。
利用不可重複性
,可以用於抽獎,保證每個使用者只能中一次獎。
zset(有序集合)
zset可能是Redis提供的最為特色的資料結構。它類似於Java的SortedSet和HashMap的結合體,一方面它是一個set,保證了內部value的唯一性,另一方面它可以給每個value賦予一個score,代表這個value的排序權重。
常用命令
# 設定值
127.0.0.1:6379> zadd books 9 java
(integer) 1
127.0.0.1:6379> zadd books 8 python
(integer) 1
127.0.0.1:6379> zadd books 7 golang
(integer) 1
# 檢視一定範圍內的值
127.0.0.1:6379> zrange books 0 -1
1) "golang"
2) "python"
3) "java"
# 刪除某個值
127.0.0.1:6379> zrem books golang
(integer) 1
# 根據score 正序排
127.0.0.1:6379> zrange books 0 -1
1) "python"
2) "java"
# 根據score 倒敘排
127.0.0.1:6379> zrevrange books 0 -1
1) "java"
2) "python"
# 檢視元素個數
127.0.0.1:6379> zcard books
(integer) 2
# 檢視某元素分值
127.0.0.1:6379> zscore books java
"9"
# 正序排名,從0開始
127.0.0.1:6379> zrank books python
(integer) 0
127.0.0.1:6379> zrank books java
(integer) 1
# 一定範圍內scor內的元素
127.0.0.1:6379> zrangebyscore books 0 8.8
1) "python"
總結
命令 | 解釋 |
---|---|
zadd | 設定值 |
zrange | 檢視一定範圍內的值 |
zrem | 刪除某個值 |
zrange | 根據score正序排 |
zrevrange | 根據score倒敘排 |
zcard | 檢視元素個數 |
zscore | 檢視某元素分值 |
zrank | 正序排名,從0開始 |
zrangebyscore | 一定範圍內scor內的元素 |
內部編碼
zset內部的排序功能是通過「跳躍列表」資料結構來實現的,它的結構非常特殊,也比較複雜。舉個例子吧,就好像一個公司,有9個員工,分為3各小組,每個小組算一個小組長(注意小組長還具備員工角色,只不過多了小組長角色)小組長再選出一個技術總監(技術總監同時具備員工、小組長、技術總監角色)
使用場景
適合排名性質的場景,比如微博熱搜,某技術網站熱門部落格等等。
總結不易,小夥伴給個贊再走吧。