Redis是目前非常主流的KV數(shù)據(jù)庫(kù),它因高性能的讀寫能力而著稱,其實(shí)還有另外一個(gè)優(yōu)勢(shì),就是Redis提供了更加豐富的數(shù)據(jù)類型馅扣,這使得Redis有著更加廣泛的使用場(chǎng)景。那Redis提供給用戶的有哪些數(shù)據(jù)類型呢着降?主要有:string(字符串)差油、List(列表)、Set(集合)、Hash(哈希)蓄喇、Zset(有序集合)发侵、HyperLogLogs(計(jì)算基數(shù)用的一種數(shù)據(jù)結(jié)構(gòu))、Streams(Redis 5.0提供一種建模日志用的全新數(shù)據(jù)結(jié)構(gòu))妆偏。
需要注意的是這里說的數(shù)據(jù)類型是指Redis值的數(shù)據(jù)類型刃鳄,而Redis鍵的類型總是string。
本文主要詳解一下前5種钱骂,也就是最常用的5種數(shù)據(jù)類型叔锐。剩下兩種可上Redis官網(wǎng)(redis.io)自行了解下。另外见秽,Redis已經(jīng)是目前Java程序員面試必問內(nèi)容愉烙,而 “Redis有哪些數(shù)據(jù)類型?” 更是面試官?gòu)埧诰蛠淼幕A(chǔ)問題解取。如果連這第一問都過不了步责,那基本上Redis這塊已經(jīng)涼涼了。
string | 字符串類型
redis的字符串類型禀苦,可以存儲(chǔ)字符串蔓肯、整數(shù)或者浮點(diǎn)數(shù)。如果存儲(chǔ)的是整數(shù)或者浮點(diǎn)數(shù)振乏,還能執(zhí)行自增或者自減操作蔗包。
并且redis的string類型是二進(jìn)制安全的,它可以包含任何數(shù)據(jù)昆码,比如一個(gè)序列化的對(duì)象气忠、一個(gè)圖片字節(jié)流等。不過存儲(chǔ)大小是有上限的-512M
這里解釋下二進(jìn)制安全的含義:簡(jiǎn)單地來說赋咽,就是字符串不是根據(jù)某種特殊的標(biāo)志位來(C語(yǔ)言的\0)解析的旧噪,無(wú)論輸入的是什么,總能保證輸出是處理的原始輸入而不是根據(jù)某種特殊格式來處理脓匿。
redis是怎么實(shí)現(xiàn)string類型的二進(jìn)制安全的呢淘钟?
答案是Sds (Simple Dynamic String,簡(jiǎn)單動(dòng)態(tài)字符串)陪毡,Redis底層定義了自己的一種數(shù)據(jù)結(jié)構(gòu)米母。(簡(jiǎn)單了解下)
typedefchar*sds;structsdshdr{// buf 已占用長(zhǎng)度intlen;// buf 剩余可用長(zhǎng)度intfree;// 實(shí)際保存字符串?dāng)?shù)據(jù)的地方charbuf[];};
操作字符串的一些命令
基礎(chǔ)set、get毡琉、del命令及示例
get keyname 獲取存儲(chǔ)在給定鍵中的值
set keyname value 設(shè)置存儲(chǔ)點(diǎn)給定鍵中的值
del keyname 刪除存儲(chǔ)在給定鍵中的值(通用命令铁瞒,適用于所有類型)
127.0.0.1:6379>sethappytodayOK127.0.0.1:6379>gethappy"today"127.0.0.1:6379>delhappy(integer) 1127.0.0.1:6379>gethappy(nil)127.0.0.1:6379>
自增和自減命令
incr keyname 將鍵存儲(chǔ)的值加1
decr kename 將鍵存儲(chǔ)的是減1
incrby keyname amount 將鍵存儲(chǔ)的值加上整數(shù)amount
decrby keyname amount 將鍵存儲(chǔ)的值減去整數(shù)amount
incrbyfloat keyname amount 將鍵存儲(chǔ)的值加上浮點(diǎn)數(shù)amount
127.0.0.1:6379>setnumber1OK127.0.0.1:6379>getnumber"1"127.0.0.1:6379>incrnumber(integer) 2127.0.0.1:6379>getnumber"2"127.0.0.1:6379>decrnumber(integer) 1127.0.0.1:6379>getnumber"1"127.0.0.1:6379>incrbynumber3(integer) 4127.0.0.1:6379>getnumber"4"127.0.0.1:6379>decrbynumber2(integer) 2127.0.0.1:6379>getnumber"2"127.0.0.1:6379>incrbyfloatnumber1.23"3.23"127.0.0.1:6379>getnumber"3.23"
子串和二進(jìn)制位命令
append keyname value 追加value值到指定字符串末尾
getrange keyname start end 獲取start到end范圍的所有字符組成的子串,包括start和end在內(nèi)
setrange keyname offset value 從偏移量 offset 開始桅滋, 用 value 參數(shù)覆寫(overwrite)鍵 keyname 儲(chǔ)存的字符串值慧耍。
getbit keyname offset 對(duì) keyname 所儲(chǔ)存的字符串值身辨,獲取指定偏移量上的位(bit)。
setbit keyname offset value 對(duì) keyname 所儲(chǔ)存的字符串值芍碧,設(shè)置或清除指定偏移量上的位(bit)煌珊。
注意redis的索引以0為開始
127.0.0.1:6379>gethello"world"127.0.0.1:6379>appendhello,java(integer) 10127.0.0.1:6379>gethello"world,java"127.0.0.1:6379>getrangehello2 5"rld,"127.0.0.1:6379>setrangehello6redis(integer) 11127.0.0.1:6379>gethello"world,redis"127.0.0.1:6379> 127.0.0.1:6379>setbitbitstr100 1(integer) 0127.0.0.1:6379>getbitbitstr100(integer) 1127.0.0.1:6379>getbitstr"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\b"127.0.0.1:6379>
其他幾個(gè)重要的命令
setnx key value 只在鍵 key 不存在的情況下, 將鍵 key 的值設(shè)置為 value泌豆;若鍵 key 已經(jīng)存在定庵, 則 SETNX 命令不做任何動(dòng)作。
setex key seconds value 將鍵 key 的值設(shè)置為 value 踪危, 并將鍵 key 的生存時(shí)間設(shè)置為 seconds 秒鐘蔬浙。如果鍵 key 已經(jīng)存在, 那么 SETEX 命令將覆蓋已有的值陨倡。
說明一下: - SETNX 是『SET if Not eXists』(如果不存在敛滋,則 SET)的簡(jiǎn)寫。命令在設(shè)置成功時(shí)返回 1 兴革, 設(shè)置失敗時(shí)返回 0 。 - SETEX命令相當(dāng)于SET key value 和 EXPIRE key seconds # 設(shè)置生存時(shí)間兩條命令的效果蜜唾,但是SETEX是一個(gè)原子操作杂曲。
127.0.0.1:6379>existsmark(integer) 0127.0.0.1:6379>setnxmarkabcd(integer) 1127.0.0.1:6379>setnxmarkdefg(integer) 0127.0.0.1:6379>getmark"abcd"127.0.0.1:6379>setexcachekey20ak98OK127.0.0.1:6379>getcachekey"ak98"127.0.0.1:6379>ttlcachekey(integer) 2
List | 列表類型
Redis的列表類型和許多程序語(yǔ)言中的列表類型類似,可以有序地存儲(chǔ)多個(gè)字符串袁余。
支持從列表的左端和右端推入或彈出元素擎勘。Redis列表的底層實(shí)現(xiàn)是壓縮列表(redis內(nèi)容自己實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu))和雙端鏈表∮卑瘢看下圖
列表操作命令詳解
lpush key value [value...]
將一個(gè)或者多個(gè)value值插入列表的表頭棚饵。如果 key 不存在,會(huì)創(chuàng)建一個(gè)空列表并執(zhí)行 LPUSH 操作掩完。當(dāng) key 存在但不是列表類型時(shí)噪漾,返回一個(gè)錯(cuò)誤。
執(zhí)行 LPUSH 命令后且蓬,會(huì)返回列表的長(zhǎng)度欣硼。
127.0.0.1:6379>lpushlistkeya(integer)1127.0.0.1:6379>lpushlistkeyabc(integer)4127.0.0.1:6379>lrangelistkey0-11)"c"2)"b"3)"a"4)"a"127.0.0.1:6379>
list類型可以加入重復(fù)的元素,這個(gè)和后面要說的set(集合類型)不同恶阴。
lrange listkey 0 -1 是獲取整個(gè)列表的內(nèi)容
類似的rpush命令是從列表右端加入元素
LPOP key
從列表的左端彈出一個(gè)值诈胜,并返回被彈出的值
127.0.0.1:6379>lrangelistkey0-11)"c"2)"b"3)"a"4)"a"127.0.0.1:6379>lpoplistkey"c"127.0.0.1:6379>lrangelistkey0-11)"b"2)"a"3)"a"127.0.0.1:6379>
lrange key start end
獲取列表key在給定start到end范圍上的所有元素值。
0表示第一個(gè)元素冯事,-1表示最后一個(gè)元素焦匈。
127.0.0.1:6379>lrangelistkey0-11)"b"2)"a"3)"a"127.0.0.1:6379>lrangelistkey011)"b"2)"a"127.0.0.1:6379>
lindex key index
獲取列表在給定index位置上的單個(gè)元素值。
可以是-1昵仅,代表最后一個(gè)元素缓熟,-2表示倒數(shù)第二個(gè)元素,以此類推。
127.0.0.1:6379>lrangelistkey0-11)"b"2)"a"3)"a"127.0.0.1:6379>lindexlistkey0"b"127.0.0.1:6379>lindexlistkey-1"a"127.0.0.1:6379>lindexlistkey3(nil)127.0.0.1:6379>
blpop key [key …] timeout
blpop 是阻塞式的彈出命令荚虚,它是lpop key 命令的阻塞版本薛夜。當(dāng)給定列表內(nèi)沒有任何元素可供彈出的時(shí)候,連接將被 blpop 命令阻塞版述,直到等待超時(shí)或發(fā)現(xiàn)可彈出元素為止梯澜。
當(dāng)給定多個(gè) key 參數(shù)時(shí),按參數(shù) key 的先后順序依次檢查各個(gè)列表渴析,彈出第一個(gè)非空列表的頭元素晚伙。
因此可以分兩種情況討論,一種是至少有一個(gè)key存在且是非空列表俭茧,則blpop命令不會(huì)阻塞咆疗,另外是blpop命令中的列表是空列表,此時(shí)會(huì)在超時(shí)時(shí)間內(nèi)阻塞母债。
先看下非阻塞的場(chǎng)景午磁,返回值是第一個(gè)非空列表名和被彈出元素。
127.0.0.1:6379>lpushlist1hellojava(integer)2127.0.0.1:6379>lpushlist2helloredis(integer)2127.0.0.1:6379>blpoplist2list1list301)"list2"2)"redis"127.0.0.1:6379>
阻塞的場(chǎng)景毡们,在執(zhí)行了blpop book1 book2 300 命令后會(huì)一直阻塞住迅皇。
127.0.0.1:6379>existsbook1(integer) 0127.0.0.1:6379>existsbook2(integer) 0127.0.0.1:6379>blpopbook1book2300
這個(gè)時(shí)候,我們?nèi)绻陂_另外一個(gè)redis客戶端衙熔,執(zhí)行如下lpush命令往book1列表中推入一個(gè)元素登颓。
127.0.0.1:6379>lpushbook1springboot(integer) 1127.0.0.1:6379>
此時(shí),再回到原來阻塞的客戶端红氯,已經(jīng)彈出了元素框咙。
127.0.0.1:6379>existsbook1(integer) 0127.0.0.1:6379>existsbook2(integer) 0127.0.0.1:6379>blpopbook1book23001) "book1"2) "springboot"(237.45s)127.0.0.1:6379>
通過利用Redis列表類型的阻塞式命令的特性,我們最容易想到的就是可以用它實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的消息隊(duì)列痢甘。
set | 集合類型
Redis的集合以無(wú)序的方式存儲(chǔ)多個(gè)不同的元素喇嘱。這里要注意的是無(wú)序和不同。
除了對(duì)集合能快速執(zhí)行添加产阱、刪除婉称、檢查一個(gè)元素是否在集合中之外,還可以對(duì)多個(gè)集合執(zhí)行交集构蹬、并集和差集運(yùn)算王暗。
底層實(shí)現(xiàn)概述
Redis的集合類型底層實(shí)現(xiàn)主要是通過一種叫做字典的數(shù)據(jù)結(jié)構(gòu)。不過Redis為了追求極致的性能庄敛,會(huì)根據(jù)存儲(chǔ)的值是否是整數(shù)俗壹,選擇一種intset的數(shù)據(jù)結(jié)構(gòu)。當(dāng)滿足一定條件后藻烤,會(huì)切換成字典的實(shí)現(xiàn)绷雏。
這里大概解釋下字典: 其實(shí)是由一集鍵值對(duì)(key-value pairs)組成头滔, 各個(gè)鍵值對(duì)的鍵各不相同, 程序可以添加新的鍵值對(duì)到字典中涎显, 或者基于鍵進(jìn)行查找坤检、更新或刪除等操作。
Redis的set(集合)在使用字典數(shù)據(jù)結(jié)構(gòu)保存數(shù)據(jù)時(shí)期吓,將元素保存到字典的鍵里面早歇, 而字典的值則統(tǒng)一設(shè)為 NULL 。
集合類型操作命令詳解
sadd key member [member...]
將一個(gè)或者多個(gè)元素添加到集合key中讨勤,已存在于集合中的元素將被忽略箭跳。返回新添加的元素?cái)?shù)量,不包括忽略的元素潭千。
srem key member [member...]
移除集合中的一個(gè)或多個(gè)元素谱姓,不存在的元素將被忽略。返回被成功移除的元素?cái)?shù)量刨晴。
sismember key meber
檢查元素member是否存在于集合key中屉来。如果是返回1,不是或者key不存在狈癞,返回0奶躯。
scard key?返回集合包含的元素?cái)?shù)量
spop key?隨機(jī)移除集合中的一個(gè)元素,并返回被移除元素亿驾。
smembers key?返回集合中包含的所有元素
127.0.0.1:6379>saddset1javaspringredis(integer)3127.0.0.1:6379>smembersset11)"redis"2)"spring"3)"java"127.0.0.1:6379>scardset1(integer)3127.0.0.1:6379>sremset1spring(integer)1127.0.0.1:6379>sismemberset1spring(integer)0127.0.0.1:6379>smembersset11)"redis"2)"java"127.0.0.1:6379>saddset1mysqlspring(integer)2127.0.0.1:6379>spopset1"redis"127.0.0.1:6379>smembersset11)"mysql"2)"spring"3)"java"127.0.0.1:6379>
下面是一些用于處理多個(gè)集合的一些命令
sdiff key [key...]?返回存在于第一個(gè)集合,但不存在于其他集合中的元素(數(shù)學(xué)上的差集運(yùn)算)
sinter key [key...]?返回同時(shí)存在于所有集合中的元素(數(shù)學(xué)上的交集運(yùn)算)?sunion key [key...]?返回至少存在于一個(gè)集合中的元素(數(shù)學(xué)上的并集運(yùn)算)
127.0.0.1:6379>smembersset11)"mysql"2)"spring"3)"java"127.0.0.1:6379>smembersset21)"mysql"2)"springboot"3)"redis"127.0.0.1:6379>sdiffset1set21)"java"2)"spring"127.0.0.1:6379>sinterset1set21)"mysql"127.0.0.1:6379>sunionset1set21)"mysql"2)"springboot"3)"java"4)"spring"5)"redis"127.0.0.1:6379>
hash | 散列表(哈希表)
Redis的hash類型其實(shí)就是一個(gè)縮減版的redis账嚎。它存儲(chǔ)的是鍵值對(duì)莫瞬,將多個(gè)鍵值對(duì)存儲(chǔ)到一個(gè)redis鍵里面。
底層實(shí)現(xiàn)概述
hash類型的底層主要也是基于字典這種數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn)的郭蕉。
redis內(nèi)部在實(shí)現(xiàn)hash數(shù)據(jù)類型的時(shí)候是使用了兩種數(shù)據(jù)結(jié)構(gòu)疼邀。在創(chuàng)建一個(gè)空的hash表時(shí),默認(rèn)使用的是ziplist的數(shù)據(jù)結(jié)構(gòu)召锈,滿足一定條件后會(huì)轉(zhuǎn)成字典的形式旁振。
散列表操作命令詳解
hmget hash-key key [key...]?從散列表里面獲取一個(gè)或多個(gè)鍵的值
hmset hash-key key value [key value...]?為散列表里面的一個(gè)或多個(gè)鍵設(shè)置值?hdel hash-key key [key...]?刪除散列表里面的一個(gè)或多個(gè)鍵值對(duì),返回刪除成功的鍵值對(duì)的數(shù)量
hlen hash-key?返回散列表包含的鍵值對(duì)的數(shù)量
hexists hash-key key?檢查給定的鍵是否存在于散列表中
hkeys hash-key?獲取散列包含的所有鍵
hvals hash-key?獲取散列包含的所有值
hgetall hash-key?獲取散列包含的所有鍵值對(duì)
127.0.0.1:6379>hmsethash1usernametomemail123@123year12OK127.0.0.1:6379>hmgethash1email1)"123@123"127.0.0.1:6379>hlenhash1(integer)3127.0.0.1:6379>hdelhash1year(integer)1127.0.0.1:6379>hexistshash1year(integer)0127.0.0.1:6379>hkeyshash11)"username"2)"email"127.0.0.1:6379>hvalshash11)"tom"2)"123@123"127.0.0.1:6379>hgetallhash11)"username"2)"tom"3)"email"4)"123@123"127.0.0.1:6379>
zset | 有序集合
有序集合相比較于集合涨岁,多個(gè)有序兩個(gè)字拐袜,我們知道set集合類型存儲(chǔ)的元素是無(wú)序的,那Redis有序集合是怎么保證有序的梢薪?使用分值蹬铺,有序集合里存儲(chǔ)著成員與分值之間的映射,并提供了分值處理命令秉撇,以及根據(jù)分值的大小有序地獲取成員或分值的命令甜攀。
底層實(shí)現(xiàn)概述
Redis有序集合的實(shí)現(xiàn)使用了一種叫跳躍表的數(shù)據(jù)結(jié)構(gòu)(簡(jiǎn)稱跳表秋泄,可自行查閱),同時(shí)也使用到了前面提到的壓縮列表规阀。也是滿足一定條件的話恒序,會(huì)自行轉(zhuǎn)換。
有序集合操作命令詳解
zadd z-key score memer [score member...] 將帶有給定分值的成員添加到有序集合里面
zrem z-key member [member...] 從有序集合里面移除給定的成員谁撼,并返回被移除成員的數(shù)量
zcard z-key 返回有序集合包含的成員數(shù)量
zincrby z-key increment member 將member成員的分值加上increment
zcount z-key min max 返回分值介于min和max之間的成員數(shù)量
zrank z-key member 返回成員member在有序集合中的排名
zscore z-key member 返回成員member的分值
zrange z-key start stop [withscores] 返回有序集合中排名介于start和stop之間的成員歧胁,如果給定了可選的withscores選項(xiàng),name命令會(huì)將成員的分值也一并返回彤敛。
zrevrank z-key member 返回有序集合里成員member的排名与帆,成員按照分值從大到小排列。
zrevrange z-key start stop 返回有序集合給定排名范圍內(nèi)的成員墨榄,成員按照分值從大到小排列玄糟。
zrangebyscore z-key min max 返回有序集合中分值介于min和max之間的所有成員
127.0.0.1:6379>zaddzset110a12b1c3d20e(integer)5127.0.0.1:6379>zcardzset1(integer)5127.0.0.1:6379>zcountzset1210(integer)2127.0.0.1:6379>zrankzset1d(integer)1127.0.0.1:6379>zscorezset1e"20"127.0.0.1:6379>zrangezset1351)"b"2)"e"127.0.0.1:6379>zrevrankzset1d(integer)3127.0.0.1:6379>zrevrangezset1351)"d"2)"c"127.0.0.1:6379>zrangebyscorezset15101)"a"127.0.0.1:6379>
原文鏈接:https://www.toutiao.com/a6996609709968982536/?log_from=1421a94b2cf08_1641554260183