字符串对象
字符串对象编码
字符串对象的编码可以是int
,raw
或者embstr
类型
int 型
如果一个字符串对象保存的是整数值, 并且这个整数值用long类型来表示, 那么字符串对象会将整数值保存在字符串对象结构的ptr
属性里面, 并将字符串编码设置为int.
redis> set number 10086 OK redis> OBJECT ENCODING number "int"
raw 型
如果字符串对象保存的是一个字符串值, 并且这个字符串值的长度大于32(在3.0版本测试为40
)字节,那么字符串对象将使用一个简单动态字符串保存这个字符串值。 并将对象的编码设置为raw.
以下测试在:3.0.0
版本上测试:
redis> set msg "Long, long age there lived a king ..." OK redis> STRLEN story (integer) 37 redis> OBJECT ENCODING story "embstr"
embstr 型
如果字符串对象保存的是一个字符串值, 并且这个字符串值的长度小于等于32(3.0.0版本测试长度为40
)字节, 那么字符串对象将使用embstr
编码的方式来保存这个字符串值.
embstr和raw比较
-
不同点
-
raw编码会调用两次内存分别来创建
redisObject
和sdshdr
结构, 用于存储字符串对象. -
embstr
编码则通过调用一次内存分配函数来分配一块连续的空间, 空间依次包含redisObject
和sdshdr
两个结构.
-
-
相同点
-
embstr
编码和raw
编码的字符串对象执行命令时产生的效果是相同的.
-
embstr的优势
-
embstr编码将创建字符串对象所需的内存分配次数从raw编码的两次降为一次
-
释放embstr编码的字符串对象只需要调用一次内存释放函数, 而释放raw编码的字符串对象需要调用两次内存释放函数
-
因为
embstr
编码的字符串对象的所有数据都保存在一块连续的内存里面, 所以这种编码的字符串对象比起raw编码的字符串独享能够更好地利用缓存带来的优势.
可以用long double
类型表示的浮点数在Redis中也是作为字符串
值保存的。如果我们要保存一个浮点数到字符串里面, 那么程序要先将这个浮点数转换成字符串值, 然后保存转换所得的字符串值.
redis> set pi 3.14 OK redis> OBJECT ENCODING pi "embstr"
浮点数的操作
在对浮点数执行操作时(如运算操作), Redis需要将保存的字符串转换为浮点数, 执行操作之后, 再将最后的结果转换为字符串值. 并继续保存在字符串对象里面。
redis>INCRBYFLOAT pi 2.0 "5.14" redis> OBJECT ENCODING pi "embstr"
字符串对象保存各类型值的编码方式
值 | 编码 |
---|---|
可以用long类型保存的整数 | int |
可以用long double类型保存的浮点数 | embstr或者raw |
字符串值或者因为太大而没办法用long类型表示的整数, 又或者因为长度太大而没办法用long double 类型表示的浮点数 |
embstr或者raw |
字符串对象编码的转换
-
int 编码的字符串对象和embstr编码的字符串对象在条件满足的情况下, 会被转换为raw编码的字符串对象.
-
对int编码的字符串对象来说, 如果我们向对象执行了一些命令, 使得这个对象保存的不再是整数, 而是一个字符串, 那么字符串对象的编码将从
int
变为raw
-
对于
embstr
编码的字符串没有任何修改的程序, 所以embstr
编码的字符串对象实际上是只读
的。 -
当我们对
embstr
编码的字符串对象执行任何修改命令时, 程序会先将对象的编码从embstr
转换为raw
, 然后再执行修改命令. 所以embstr
编码的字符串对象在执行修改命令之后, 总会变成一个raw
编码的字符串对象。
字符串命令的实现
命令 | int编码的实现方法 | embstr编码的实现方法 | raw编码的实现方法 |
---|---|---|---|
SET | 使用int编码保存值 | 使用embstr编码保存值 | 使用raw编码保存值 |
GET | 拷贝对象所保存的整数值, 将这个拷贝转换成字符串信息, 然后想客户端返回这个字符串值 | 指向向客户端返回字符串 | 直接向客户端返回字符串值 |
APPEND | 将对象转换成raw编码, 然后按raw编码的方式执行此操作 | 将对象转换成raw编码, 然后按raw编码的方式执行此操作 | 调用sdscatlen 函数, 将给定字符串追加到现有字符串的末尾 |
INCRBYFLOAT | 去除整数值并将其转换为long double 类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来 |
取出字符串值并尝试将其转换成long double 类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来。如果字符串值不能被转换成浮点数, 那么向客户端返回一个错误 |
取出字符串值并尝试将其转换成long double 类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来。如果字符串值不能被转换成浮点数, 那么向客户端返回一个错误 |
INCRBY | 对证书值进行加法计算, 得出的计算结果会作为整数保存起来 | embstr编码不能执行此命令, 客户端返回一个错误 | raw编码不能执行此命令, 向客户端返回一个错误 |
DECRBY | 对整数值进行减法计算, 得出的计算结果会作为整数倍保存起来 | embstr编码不能执行此命令, 向客户端返回一个错误 | raw编码不能执行此命令, 想客户端返回一个错误 |
STRLEN | 拷贝对象所保存的整数值, 将这个拷贝转换成字符串值, 计算并返回这个字符串值的长度 | 调用sdslen 函数, 返回字符串长度 |
调用sdslen函数, 返回字符串的长度 |
SETRANGE | 将对象转转成raw编码, 然后按raw编码的方式执行此命令 | 将对象转转成raw编码, 然后按raw编码的方式执行此命令 | 将字符串特定索引上的值设置为给定的字符 |
GETRANGE | 拷贝对象所保存的整数值, 将这个拷贝转换成为字符串值, 然后取出并返回字符串指定索引上的字符 | 直接取出返回字符串指定索引上的字符 | 直接取出并返回字符串指定索引上的字符 |