Redis 字符串對(duì)象

2018-08-02 14:48 更新

字符串對(duì)象的編碼可以是 int 、 raw 或者 embstr 。

如果一個(gè)字符串對(duì)象保存的是整數(shù)值, 并且這個(gè)整數(shù)值可以用 long 類型來(lái)表示, 那么字符串對(duì)象會(huì)將整數(shù)值保存在字符串對(duì)象結(jié)構(gòu)的 ptr屬性里面(將 void* 轉(zhuǎn)換成 long ), 并將字符串對(duì)象的編碼設(shè)置為 int 。

舉個(gè)例子, 如果我們執(zhí)行以下 SET 命令, 那么服務(wù)器將創(chuàng)建一個(gè)如圖 8-1 所示的 int 編碼的字符串對(duì)象作為 number 鍵的值:

redis> SET number 10086
OK

redis> OBJECT ENCODING number
"int"

如果字符串對(duì)象保存的是一個(gè)字符串值, 并且這個(gè)字符串值的長(zhǎng)度大于 39 字節(jié), 那么字符串對(duì)象將使用一個(gè)簡(jiǎn)單動(dòng)態(tài)字符串(SDS)來(lái)保存這個(gè)字符串值, 并將對(duì)象的編碼設(shè)置為 raw 。

舉個(gè)例子, 如果我們執(zhí)行以下命令, 那么服務(wù)器將創(chuàng)建一個(gè)如圖 8-2 所示的 raw 編碼的字符串對(duì)象作為 story 鍵的值:

redis> SET story "Long, long, long ago there lived a king ..."
OK

redis> STRLEN story
(integer) 43

redis> OBJECT ENCODING story
"raw"

如果字符串對(duì)象保存的是一個(gè)字符串值, 并且這個(gè)字符串值的長(zhǎng)度小于等于 39 字節(jié), 那么字符串對(duì)象將使用 embstr 編碼的方式來(lái)保存這個(gè)字符串值。

embstr 編碼是專門用于保存短字符串的一種優(yōu)化編碼方式, 這種編碼和 raw 編碼一樣, 都使用 redisObject 結(jié)構(gòu)和 sdshdr 結(jié)構(gòu)來(lái)表示字符串對(duì)象, 但 raw 編碼會(huì)調(diào)用兩次內(nèi)存分配函數(shù)來(lái)分別創(chuàng)建 redisObject 結(jié)構(gòu)和 sdshdr 結(jié)構(gòu), 而 embstr 編碼則通過(guò)調(diào)用一次內(nèi)存分配函數(shù)來(lái)分配一塊連續(xù)的空間, 空間中依次包含 redisObject 和 sdshdr 兩個(gè)結(jié)構(gòu), 如圖 8-3 所示。

embstr 編碼的字符串對(duì)象在執(zhí)行命令時(shí), 產(chǎn)生的效果和 raw 編碼的字符串對(duì)象執(zhí)行命令時(shí)產(chǎn)生的效果是相同的, 但使用 embstr 編碼的字符串對(duì)象來(lái)保存短字符串值有以下好處:

  1. embstr 編碼將創(chuàng)建字符串對(duì)象所需的內(nèi)存分配次數(shù)從 raw 編碼的兩次降低為一次。
  2. 釋放 embstr 編碼的字符串對(duì)象只需要調(diào)用一次內(nèi)存釋放函數(shù), 而釋放 raw 編碼的字符串對(duì)象需要調(diào)用兩次內(nèi)存釋放函數(shù)。
  3. 因?yàn)?nbsp;embstr 編碼的字符串對(duì)象的所有數(shù)據(jù)都保存在一塊連續(xù)的內(nèi)存里面, 所以這種編碼的字符串對(duì)象比起 raw 編碼的字符串對(duì)象能夠更好地利用緩存帶來(lái)的優(yōu)勢(shì)。

作為例子, 以下命令創(chuàng)建了一個(gè) embstr 編碼的字符串對(duì)象作為 msg 鍵的值, 值對(duì)象的樣子如圖 8-4 所示:

redis> SET msg "hello"
OK

redis> OBJECT ENCODING msg
"embstr"

最后要說(shuō)的是, 可以用 long double 類型表示的浮點(diǎn)數(shù)在 Redis 中也是作為字符串值來(lái)保存的: 如果我們要保存一個(gè)浮點(diǎn)數(shù)到字符串對(duì)象里面, 那么程序會(huì)先將這個(gè)浮點(diǎn)數(shù)轉(zhuǎn)換成字符串值, 然后再保存起轉(zhuǎn)換所得的字符串值。

舉個(gè)例子, 執(zhí)行以下代碼將創(chuàng)建一個(gè)包含 3.14 的字符串表示 "3.14" 的字符串對(duì)象:

redis> SET pi 3.14
OK

redis> OBJECT ENCODING pi
"embstr"

在有需要的時(shí)候, 程序會(huì)將保存在字符串對(duì)象里面的字符串值轉(zhuǎn)換回浮點(diǎn)數(shù)值, 執(zhí)行某些操作, 然后再將執(zhí)行操作所得的浮點(diǎn)數(shù)值轉(zhuǎn)換回字符串值, 并繼續(xù)保存在字符串對(duì)象里面。

舉個(gè)例子, 如果我們執(zhí)行以下代碼的話:

redis> INCRBYFLOAT pi 2.0
"5.14"

redis> OBJECT ENCODING pi
"embstr"

那么程序首先會(huì)取出字符串對(duì)象里面保存的字符串值 "3.14" , 將它轉(zhuǎn)換回浮點(diǎn)數(shù)值 3.14 , 然后把 3.14 和 2.0 相加得出的值 5.14 轉(zhuǎn)換成字符串 "5.14" , 并將這個(gè) "5.14" 保存到字符串對(duì)象里面。

表 8-6 總結(jié)并列出了字符串對(duì)象保存各種不同類型的值所使用的編碼方式。


表 8-6 字符串對(duì)象保存各類型值的編碼方式

編碼
可以用 long 類型保存的整數(shù)。 int
可以用 long double 類型保存的浮點(diǎn)數(shù)。 embstr 或者 raw
字符串值, 或者因?yàn)殚L(zhǎng)度太大而沒(méi)辦法用 long 類型表示的整數(shù), 又或者因?yàn)殚L(zhǎng)度太大而沒(méi)辦法用long double 類型表示的浮點(diǎn)數(shù)。 embstr 或者 raw

編碼的轉(zhuǎn)換

int 編碼的字符串對(duì)象和 embstr 編碼的字符串對(duì)象在條件滿足的情況下, 會(huì)被轉(zhuǎn)換為 raw 編碼的字符串對(duì)象。

對(duì)于 int 編碼的字符串對(duì)象來(lái)說(shuō), 如果我們向?qū)ο髨?zhí)行了一些命令, 使得這個(gè)對(duì)象保存的不再是整數(shù)值, 而是一個(gè)字符串值, 那么字符串對(duì)象的編碼將從 int 變?yōu)?nbsp;raw 。

在下面的示例中, 我們通過(guò) APPEND 命令, 向一個(gè)保存整數(shù)值的字符串對(duì)象追加了一個(gè)字符串值, 因?yàn)樽芳硬僮髦荒軐?duì)字符串值執(zhí)行, 所以程序會(huì)先將之前保存的整數(shù)值 10086 轉(zhuǎn)換為字符串值 "10086" , 然后再執(zhí)行追加操作, 操作的執(zhí)行結(jié)果就是一個(gè) raw 編碼的、保存了字符串值的字符串對(duì)象:

redis> SET number 10086
OK

redis> OBJECT ENCODING number
"int"

redis> APPEND number " is a good number!"
(integer) 23

redis> GET number
"10086 is a good number!"

redis> OBJECT ENCODING number
"raw"

另外, 因?yàn)?Redis 沒(méi)有為 embstr 編碼的字符串對(duì)象編寫任何相應(yīng)的修改程序 (只有 int 編碼的字符串對(duì)象和 raw 編碼的字符串對(duì)象有這些程序), 所以 embstr 編碼的字符串對(duì)象實(shí)際上是只讀的: 當(dāng)我們對(duì) embstr 編碼的字符串對(duì)象執(zhí)行任何修改命令時(shí), 程序會(huì)先將對(duì)象的編碼從 embstr 轉(zhuǎn)換成 raw , 然后再執(zhí)行修改命令; 因?yàn)檫@個(gè)原因, embstr 編碼的字符串對(duì)象在執(zhí)行修改命令之后, 總會(huì)變成一個(gè) raw 編碼的字符串對(duì)象。

以下代碼展示了一個(gè) embstr 編碼的字符串對(duì)象在執(zhí)行 APPEND 命令之后, 對(duì)象的編碼從 embstr 變?yōu)?nbsp;raw 的例子:

redis> SET msg "hello world"
OK

redis> OBJECT ENCODING msg
"embstr"

redis> APPEND msg " again!"
(integer) 18

redis> OBJECT ENCODING msg
"raw"

字符串命令的實(shí)現(xiàn)

因?yàn)樽址I的值為字符串對(duì)象, 所以用于字符串鍵的所有命令都是針對(duì)字符串對(duì)象來(lái)構(gòu)建的, 表 8-7 列舉了其中一部分字符串命令, 以及這些命令在不同編碼的字符串對(duì)象下的實(shí)現(xiàn)方法。


表 8-7 字符串命令的實(shí)現(xiàn)

命令 int 編碼的實(shí)現(xiàn)方法 embstr 編碼的實(shí)現(xiàn)方法 raw 編碼的實(shí)現(xiàn)方法
SET 使用 int 編碼保存值。 使用 embstr 編碼保存值。 使用 raw 編碼保存值。
GET 拷貝對(duì)象所保存的整數(shù)值, 將這個(gè)拷貝轉(zhuǎn)換成字符串值, 然后向客戶端返回這個(gè)字符串值。 直接向客戶端返回字符串值。 直接向客戶端返回字符串值。
APPEND 將對(duì)象轉(zhuǎn)換成 raw 編碼, 然后按raw 編碼的方式執(zhí)行此操作。 將對(duì)象轉(zhuǎn)換成 raw 編碼, 然后按raw 編碼的方式執(zhí)行此操作。 調(diào)用 sdscatlen 函數(shù), 將給定字符串追加到現(xiàn)有字符串的末尾。
INCRBYFLOAT 取出整數(shù)值并將其轉(zhuǎn)換成 longdouble 類型的浮點(diǎn)數(shù), 對(duì)這個(gè)浮點(diǎn)數(shù)進(jìn)行加法計(jì)算, 然后將得出的浮點(diǎn)數(shù)結(jié)果保存起來(lái)。 取出字符串值并嘗試將其轉(zhuǎn)換成long double 類型的浮點(diǎn)數(shù), 對(duì)這個(gè)浮點(diǎn)數(shù)進(jìn)行加法計(jì)算, 然后將得出的浮點(diǎn)數(shù)結(jié)果保存起來(lái)。 如果字符串值不能被轉(zhuǎn)換成浮點(diǎn)數(shù), 那么向客戶端返回一個(gè)錯(cuò)誤。 取出字符串值并嘗試將其轉(zhuǎn)換成 longdouble 類型的浮點(diǎn)數(shù), 對(duì)這個(gè)浮點(diǎn)數(shù)進(jìn)行加法計(jì)算, 然后將得出的浮點(diǎn)數(shù)結(jié)果保存起來(lái)。 如果字符串值不能被轉(zhuǎn)換成浮點(diǎn)數(shù), 那么向客戶端返回一個(gè)錯(cuò)誤。
INCRBY 對(duì)整數(shù)值進(jìn)行加法計(jì)算, 得出的計(jì)算結(jié)果會(huì)作為整數(shù)被保存起來(lái)。 embstr 編碼不能執(zhí)行此命令, 向客戶端返回一個(gè)錯(cuò)誤。 raw 編碼不能執(zhí)行此命令, 向客戶端返回一個(gè)錯(cuò)誤。
DECRBY 對(duì)整數(shù)值進(jìn)行減法計(jì)算, 得出的計(jì)算結(jié)果會(huì)作為整數(shù)被保存起來(lái)。 embstr 編碼不能執(zhí)行此命令, 向客戶端返回一個(gè)錯(cuò)誤。 raw 編碼不能執(zhí)行此命令, 向客戶端返回一個(gè)錯(cuò)誤。
STRLEN 拷貝對(duì)象所保存的整數(shù)值, 將這個(gè)拷貝轉(zhuǎn)換成字符串值, 計(jì)算并返回這個(gè)字符串值的長(zhǎng)度。 調(diào)用 sdslen 函數(shù), 返回字符串的長(zhǎng)度。 調(diào)用 sdslen 函數(shù), 返回字符串的長(zhǎng)度。
SETRANGE 將對(duì)象轉(zhuǎn)換成 raw 編碼, 然后按raw 編碼的方式執(zhí)行此命令。 將對(duì)象轉(zhuǎn)換成 raw 編碼, 然后按raw 編碼的方式執(zhí)行此命令。 將字符串特定索引上的值設(shè)置為給定的字符。
GETRANGE 拷貝對(duì)象所保存的整數(shù)值, 將這個(gè)拷貝轉(zhuǎn)換成字符串值, 然后取出并返回字符串指定索引上的字符。 直接取出并返回字符串指定索引上的字符。 直接取出并返回字符串指定索引上的字符。
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)