博主从事java 只有1年多,越学习越觉得自己知道的很少,期间有时候还觉得自己java好像不错的样子,现在来看,扯淡,哈哈。
套用人生几大状态:其实很多时候人都是处于第一阶段,以为自己懂的很多,当然这是针对大多人的,少部分人又天赋,智商又高,搞起编程得心应手,而我们这种不聪明又没天赋的,只能尽量努力提高自己。时刻警醒,要做2阶段的人。求知探索。
1、不知道自己不知道(自以为是);
2、知道自己不知道(求知探索);
3、知道自己知道(探索规律);
4、不知道自己知道(空杯心态)。
此篇日志参考于如下资料:,自己写一遍,去redis环境测试一遍,能够加深不少印象,光看,还是不行的。
http://redisbook.com/
redis的对象
redis使用对象来表示键值对,也就是说新建一个redis键值对时,会创建2个对象,一个是键对象,一个是值对象。每个对象都是由redisObject结构表示:
typedef struct redisObject {
// 类型
unsigned type:4;
// 编码
unsigned encoding:4;
// 指向底层实现数据结构的指针
void *ptr;
// ...
} robj;
这个结构先不去关心,只需要知道就行,有C基础应该就能看懂,C中的结构体就是用struct表示的。
类型
对象的type属性记录的是对象的类型,这个值可以是下面的一种:对于键值对的键来说的话,其实一般都是字符串对象,而值可能有多种多样的类型
类型常量 对象的名称
REDIS_STRING 字符串对象
REDIS_LIST 列表对象
REDIS_HASH 哈希对象
REDIS_SET 集合对象
REDIS_ZSET 有序集合对象
实践
这个时候其实我对于命令还只是停留在set,get阶段,不过不要紧,先有个感性的认识,理性的认识慢慢来。
#String 类型
127.0.0.1:6379> set abc haha
OK
127.0.0.1:6379> get abc
"haha"
127.0.0.1:6379> type abc
string
127.0.0.1:6379>
#list 类型
127.0.0.1:6379> type abclist
list
127.0.0.1:6379>
#hash类型
127.0.0.1:6379> hmset srudent name tom age 15 address nanjing
OK
127.0.0.1:6379> hmget srudent name age address
1) "tom"
2) "15"
3) "nanjing"
127.0.0.1:6379> type srudent
hash
另外还有集合和有序集合这两个基本的类型,分别是set和zset,不去列举了。几个类型都在下面。OBJECT ENCODING命令可以查看编码方式
对象 | 对象 type 属性的值 | TYPE 命令的输出 |
---|---|---|
字符串对象 | REDIS_STRING | "string" |
列表对象 | REDIS_LIST | "list" |
哈希对象 | REDIS_HASH | "hash" |
集合对象 | REDIS_SET | "set" |
有序集合对象 | REDIS_ZSET | "zset" |
编码和底层实现
这一段我也不清楚,暂时先记录下,作为对比,以后深入学习之后再说:
编码常量 | 编码所对应的底层数据结构 |
---|---|
REDIS_ENCODING_INT | long 类型的整数 |
REDIS_ENCODING_EMBSTR | embstr 编码的简单动态字符串 |
REDIS_ENCODING_RAW | 简单动态字符串 |
REDIS_ENCODING_HT | 字典 |
REDIS_ENCODING_LINKEDLIST | 双端链表 |
REDIS_ENCODING_ZIPLIST | 压缩列表 |
REDIS_ENCODING_INTSET | 整数集合 |
REDIS_ENCODING_SKIPLIST | 跳跃表和字典 |
类型 | 编码 | 对象 |
---|---|---|
REDIS_STRING | REDIS_ENCODING_INT | 使用整数值实现的字符串对象。 |
REDIS_STRING | REDIS_ENCODING_EMBSTR | 使用 embstr 编码的简单动态字符串实现的字符串对象。 |
REDIS_STRING | REDIS_ENCODING_RAW | 使用简单动态字符串实现的字符串对象。 |
REDIS_LIST | REDIS_ENCODING_ZIPLIST | 使用压缩列表实现的列表对象。 |
REDIS_LIST | REDIS_ENCODING_LINKEDLIST | 使用双端链表实现的列表对象。 |
REDIS_HASH | REDIS_ENCODING_ZIPLIST | 使用压缩列表实现的哈希对象。 |
REDIS_HASH | REDIS_ENCODING_HT | 使用字典实现的哈希对象。 |
REDIS_SET | REDIS_ENCODING_INTSET | 使用整数集合实现的集合对象。 |
REDIS_SET | REDIS_ENCODING_HT | 使用字典实现的集合对象。 |
REDIS_ZSET | REDIS_ENCODING_ZIPLIST | 使用压缩列表实现的有序集合对象。 |
REDIS_ZSET | REDIS_ENCODING_SKIPLIST | 使用跳跃表和字典实现的有序集合对象。 |
字符串对象
字符串对象的编码可以是 int ,raw,embstr
1.设置的是数字型的键值对,编码就是int
127.0.0.1:6379> set num 10010
OK
127.0.0.1:6379> type num
string
127.0.0.1:6379> object encoding num
"int"
127.0.0.1:6379>
底层结构如下:图直接copy下来,可以看见ptr指针直接指向 这个值
2.设置的是字符串键值对,这其中根据字符串长度的不同,会有不同的表现
2.1 长度小于39的话,会使用embstr的编码
127.0.0.1:6379> set key1 abc
OK
127.0.0.1:6379> type key1
string
127.0.0.1:6379> object encoding key1
"embstr"
127.0.0.1:6379>
embstr是专门针对短字符串的一种优化,和raw一样,都使用redisObject和sdshdr结构表示,但是embstr只调用一次内存分配函数来分配一块连续的空间
因此2.1中set的 key1就如下结构:图是直接copy的,可以看见sdshdr中有free,len和buf,buf中存放的是字符串,以\0结尾,和C一致
2.2 长度超过 39,使用的是 raw编码方式
127.0.0.1:6379> set key2 "abc cdrfdsertg kgjfhdurhfg hff"
OK
127.0.0.1:6379> type key1
string
127.0.0.1:6379> type key2
string
127.0.0.1:6379> object encoding key2
"raw"
127.0.0.1:6379>
raw方式的不同点在于调用两次内存分配函数创建redisObject和sdshdr结构,也就是这种方式的存放地址不是连续的,但是内部都是一样的
2.3浮点数也是一样可以保存的,但是会转换成字符串
127.0.0.1:6379> set key3 3.14
OK
127.0.0.1:6379> type key3
string
127.0.0.1:6379> object encoding key3
"embstr"
127.0.0.1:6379>
总结下:
值 | 编码 |
---|---|
可以用 long 类型保存的整数。 | int |
可以用 long double 类型保存的浮点数。 | embstr 或者 raw |
字符串值, 或者因为长度太大而没办法用 long 类型表示的整数, 又或者因为长度太大而没办法用 long double 类型表示的浮点数。 | embstr 或者 raw |
编码的转换
int 和embstr子啊特定条件会向raw转换,不难理解,如果int 拼接字符串或者字符串长度太长,会转换
比如1:
127.0.0.1:6379> get num
"10010"
127.0.0.1:6379> append num "is a num"
(integer) 13
127.0.0.1:6379> get num
"10010is a num"
127.0.0.1:6379> object encoding num
"raw"
127.0.0.1:6379>
比如2: redis中没有对embstr编码的字符串提供修改程序,所以embstr都是只读的,因此任何对embstr做的修改,都会先将embstr转换成raw,再执行修改。
127.0.0.1:6379> set key5 abc
OK
127.0.0.1:6379> object encoding abc
"embstr"
127.0.0.1:6379> append key5 " is a english"
(integer) 16
127.0.0.1:6379> obejct encoding key5
(error) ERR unknown command 'obejct'
127.0.0.1:6379> object encoding key5
"raw"
127.0.0.1:6379>
字符串命令:
命令 | int 编码的实现方法 | embstr 编码的实现方法 | raw 编码的实现方法 |
---|---|---|---|
SET | 使用 int 编码保存值。 | 使用 embstr 编码保存值。 | 使用 raw 编码保存值。 |
GET | 拷贝对象所保存的整数值, 将这个拷贝转换成字符串值, 然后向客户端返回这个字符串值。 | 直接向客户端返回字符串值。 | 直接向客户端返回字符串值。 |
APPEND | 将对象转换成 raw 编码, 然后按 raw 编码的方式执行此操作。 | 将对象转换成 raw 编码, 然后按 raw 编码的方式执行此操作。 | 调用 sdscatlen 函数, 将给定字符串追加到现有字符串的末尾。 |
INCRBYFLOAT | 取出整数值并将其转换成 longdouble 类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来。 | 取出字符串值并尝试将其转换成long double 类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来。 如果字符串值不能被转换成浮点数, 那么向客户端返回一个错误。 | 取出字符串值并尝试将其转换成 longdouble 类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来。 如果字符串值不能被转换成浮点数, 那么向客户端返回一个错误。 |
INCRBY | 对整数值进行加法计算, 得出的计算结果会作为整数被保存起来。 | embstr 编码不能执行此命令, 向客户端返回一个错误。 | raw 编码不能执行此命令, 向客户端返回一个错误。 |
DECRBY | 对整数值进行减法计算, 得出的计算结果会作为整数被保存起来。 | embstr 编码不能执行此命令, 向客户端返回一个错误。 | raw 编码不能执行此命令, 向客户端返回一个错误。 |
STRLEN | 拷贝对象所保存的整数值, 将这个拷贝转换成字符串值, 计算并返回这个字符串值的长度。 | 调用 sdslen 函数, 返回字符串的长度。 | 调用 sdslen 函数, 返回字符串的长度。 |
SETRANGE | 将对象转换成 raw 编码, 然后按 raw 编码的方式执行此命令。 | 将对象转换成 raw 编码, 然后按 raw 编码的方式执行此命令。 | 将字符串特定索引上的值设置为给定的字符。 |
GETRANGE | 拷贝对象所保存的整数值, 将这个拷贝转换成字符串值, 然后取出并返回字符串指定索引上的字符。 | 直接取出并返回字符串指定索引上的字符。 | 直接取出并返回字符串指定索引上的字符。 |