一、redis集群测试环境搭建

参考文章:https://www.jianshu.com/p/0a2f8f80983a

redis-cli -c -h 10.96.87.129 -p 7001注意:-c是以集群模式启动redis客户端

二、redis五种不同的数据类型(value)

2.1 简单动态字符串(SDS,Simple Dynamic String)

Redis没有直接使用C语言传统的字符串表示,而是构建了一种名为简单动态字符串的抽象类型即SDS。C字符串只会作为字符串字面量用在一些无需对字符串进行修改的地方比如日志打印。另外,除了用来保存数据库中的字符串值之外,SDS还被用作缓冲区。

1、SDS的定义

struct sdshdr{   int len; //记录buf数组中已使用的字节的数量,也就是字符串的长度   int free; //记录buf数组中未使用的字节的数量   char buf[]; //字节数组,用于保存字符串
}

SDS是遵循C字符串以空字符结尾的管理,但是这一个字节是不算在SDS的len属性中的,而是额外分配的。这样做的好处是空字符对于SDS的使用者来说是透明的,且咱们又可以直接重用C字符串函数库里的函数。

2、SDS与C字符串的区别

  • 由于len属性的存在,SDS获取字符串长度复杂度为o(1),而c字符串为o(n)
  • SDS能杜绝缓冲区溢出,比如SDS的API sdscat字符串拼接操作在拼接之前会事先检查SDS空间是否足够
  • 减少修改字符串时内存重新分配次数:对于C字符串在进行增长字符串的操作时,程序需要通过内存重新分配来扩展底层数组的空间大小,如果忘了这一步会产生缓冲区溢出缩短字符串的操作,在执行操作之后,程序需要通过内存重新分配来释放字符串不再使用的那部分空间,如果忘了会造成内存泄露。而SDS通过free未使用空间实现了空间预分配惰性空间释放两种优化策略。

空间预分配:当SDS的API对一个SDS进行增加时,程序不仅会为SDS分配所必要的空间,还会为SDS分配额外的未使用空间。分配的未使用空间数量原则是:如果对SDS进行修改之后,SDS的长度len<1MB,那么程序会分配和len相同大小的未使用空间free。比如增加之后len变为13字节,那么free的长度也会变成13字节,即SDS的buf数组的实际长度是13+13+1=27字节。如果对SDS进行修改之后,SDS的长度len>=1MB,那么程序会分配1MB的未使用空间。比如进行修改之后,SDS的len变成30MB,那么程序会分配1MB的未使用空间,即SDS的buf数组的实际长度是30MB+1MB+1byte。通过这种分配策略,SDS将连续增长N次字符串所需要的内存重分配次数从必定N次降低为最多N次惰性空间释放:当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存重新分配来回收多出来的字节,而是使用free属性将这些字节的数量记录下来,并等待将来使用。通过惰性空间释放策略,SDS避免了缩短字符串时所需要的内存重分配操作,并为将来可能的增长操作带来了优化。另外SDS也提供了相应的API在需要时真正释放SDS的未使用空间,避免造成内存泄露。

  • 二进制安全:SDS的API都是二进制安全的,所有SDS API都会以处理二进制的方式来处理SDS存放在buf数组中的数据,程序不会对其中的数据做任何限制、过滤或者假设,数据写入时是什么样的,读取时就是什么样。Redis不是用这个数组保存字符,而是用它来保存一系列二进制数据。
  • 兼容部分C字符串函数:通过遵循C字符串以空字符结尾的惯例,SDS可以在需要时重用<String.h>函数库。

总结:

2.1 SDS与C字符串的区别

2.2 链表

1、链表节点以及链表的定义

被广泛用于实现Redis的各种功能,比如列表键、发布与订阅、慢查询、监视器等

typedef struct listNode{struct listNode * prev; //前置节点struct listNode * next; //后置节点void * value; //节点的值
};typedef struct list{listNode * head; //表头节点listNode * tail; //表尾节点unsigned long len; //链表所包含的节点数量void *(*dup)(void *ptr); //复制链表节点所保存的值void (*free)(void *ptr); //释放链表节点所保存的值int (*match)(void *ptr,void *key); //对比链表节点所保存的值和另一个输入值是否相等
};

2、Redis链表实现的特性

  • 双向:带有pre和next指针,获取某个节点的前置或者后置节点复杂度为O(1)
  • 无环:表头节点的prev指针和表尾节点的指针next都指向null
  • 带表头指针和表尾指针:head指针和tail指针,获取表头和表尾的复杂度为O(1)
  • 带链表长度计数器:len属性保存节点的个数,获取节点数量的复杂度为O(1)
  • 多态**:使用void*指针保存节点值,并且可以通过list结构的dup、free、match三个属性为节点值设置类型特定函数,所以链表可以保存各种不同类型的值

2.3 字典

字典又称为符号表(Symbol table)、关联数组(Associative array)或者映射(Map),是一种用于存储键值对的抽象数据结构。Redis的字典使用哈希表作为底层实现,一个哈希表可以有多个哈希表节点,每个哈希表节点就保存了字典中一个键值对。

1、哈希表定义

typedef struct dictht{dictEntry **table;//哈希表数组,数组中的每个元素都指向dict.h/dictEntry结构的指针并保存一个键值对unsigned long size;//哈希表大小unsigned long sizemask;//哈希表大小的掩码,用于计算索引值,总是等于size-1,和哈希值一起决定了键的位置unsigned long used; //该哈希表已有节点的数量
}

2、哈希表节点定义

typedef struct dictEntry{void *key;//键//值,可以是一个指针或者是一个uint64_t整数或者是int64_t整数union{void *val;uint64_tu64;int64_ts64;}v;struct dictEntry *next;//指向下个哈希表节点,形成链表。
}

3、字典的定义

typedef struct dict{dictType *type; //类型特定函数,指向dictType结构的指针,每个dictType结构保存了一簇用于操作特定类型键值对的函数。Redis为用途不同的字典设置不同的类型特定函数void*privdata; //私有数据,保存了需要传递给那些类型特定函数的可选参数dictht ht[2]; //哈希表,包含两个哈希表,一般情况只使用ht[0]哈希表,ht[1]哈希表只会在ht[0]进行rehash时使用int rehashidx; //记录了rehash目前的进度,当rehash不在进行时,值为-1
}

4、类型特定函数的定义

typedef struct dictType{unsigned int(*hashFunction)(const void *key); //计算哈希值的函数void *(*keyDup)(void *privdate,const void *key); //复制键的函数void *(*valDup)(void *privdate,const void *obj); //复制值的函数int (*keyCompare)(void *privdate,const void *key1,const void *key2); //对比键的函数void (*keyDestructor)(void *privdate, void *key); //销毁键的函数void (*valDestructor)(const void *obj); //销毁值的函数
}

5、哈希算法

添加新的键值对时,现根据key计算出key的哈希值,再根据哈希表的sizemask以及刚计算的哈希值计算出索引值。

index = hash & dict->ht[x].sizemask
即:第一步:`hash = dict->type->hashfunction(key0)`第二步:`index = hash & dict.ht[0].sizemask`

补充下当字典被用作数据库的底层实现或者哈希键的底层实现时,redis使用MurmurHash2算法计算键的哈希值,这种算法的好处是即使输入的键是规律的,仍然能给出一个很好的随机分布性。

6、解决键冲突

当有两个或两个以上的键被分配到了哈希表数组的同一个索引上时,就称为键发生了冲突。Redis的哈希表使用链地址法来解决键冲突,也就是每个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被分配到同一个索引上的多个节点可以用这个单向链表连接起来。另外,因为dictEntry节点组成的链表没有指向链表表尾的指针,所以为了速度考虑,每次将新节点添加到链表的表头位置,复杂度是O(1)

7、Rehash

当哈希表中的键值对数量太多或者太少的时候,为了让哈希表的负载因子维持在一个合理的范围内,程序需要对哈希表的大小进行相应的扩容或者缩容

  • 第一步: 为字典的ht[1]哈希表分配空间,大小取决于是扩容还是缩容,如果是扩容那么ht[1]的大小为第一个大于等于ht[0].used2的2的n次方幂,假如ht[0].used*2等于7,那么size就为2的三次方为8。如果是缩容ht[1]的大小为第一个大于等于ht[0].used的2的n次方幂
  • 第二步: 将ht[0]所有键值对重新计算hash值以及所有值并放到ht[1]哈希表对应的位置
  • 第三步:当ht[0]包含的所有键值对都迁移到了ht[1]之后,释放ht[0],将ht[1]设置为ht[1],并在ht[1]新创建一个空白哈希表

当以下任意条件满足时,程序会自动对哈希表进行扩容操作:

  • 服务器没有在执行BGSAVE命令或者BGREWRITEAOF命令,且哈希表的负载因子loadFactor>=1
  • 服务器正在执行BGSAVE命令或者BGREWRITEAOF命令,且哈希表的负载因子loadFactor>=5当负载因子loadFactor<0.1时,会自动缩容>
  • 负载因子load_factor=ht[0].used/h[0].size

8、渐进式Rehash

当在进行扩容或缩容的时候需要将ht[0]的键值对rehash到ht[1]哈希表中,但是这种rehash的动作不是一次性、集中式的,而是分多次、渐进式的。不然在键值对的数量量级比较大的时候,一次性地将这些键值对全部rehash的话可能会造成服务器在一段时间内停止服务。而渐进式rehash采用分而治之的方式,将rehash键值对所需的计算工作均摊到对字典的每次添加、删除、更新和查找操作上,从而避免了集中式rehash带来的庞大计算量。

渐进式的rehash的步骤:

  • 为ht[1]分配空间,让字典同时持有ht[0]和ht[1]两个哈希表
  • 在字典中维持一个索引计数器变量rehashidx,并将它的值设置为0表示rehash工作开始
  • 在rehash进行期间,每次对字典执行正常的添加、删除、更新、查找操作时,程序除了执行指定的操作以外,还会顺带将ht[0]哈希表在rehashidx索引上的所有键值对reash到ht[1],当rehash工作完成之后,程序将rehashidx属性的值增加1
  • 随着字典操作的不断执行,ht[0]的所有键值对都rehash到ht[1],这时rehashidx被设置为-1,表示rehash完成
  • 在渐进式的rehash过程中,字典会同时使用ht[0]和ht[1]两个哈希表,所在在此期间字典的删除、更新、查找等操作都会在两个哈希表上进行。而添加操作一律会被保存到ht[1]中,ht[0]不再进行任何添加操作。

2.4 跳跃表

一种有序数据结构,查找节点的复杂度平均O(logN)、最坏O(N)。Redis使用跳跃表作为有序集合键的底层实现之一,只在两个地方使用到了跳跃表,一个是实现有序集合键,另一个是在集群节点中用作内部数据结构

2.2 跳跃表结构

1、跳跃表节点的定义

typedef struct zskiplistNode{//层struct zskiplistLevel{struct zskiplistNode *forward; //前进指针unsigned int span; //跨度}level[];struct zskiplistNode *backward; //后退指针double score; //分值robj *obj; //成员对象
}zskiplistNode;

  • :跳跃表节点的level数组包含多个元素,每个元素都包含一个指向其他节点的指针,程序可以通过这些层来加快访问其他节点的速度,一般来说层数越多速度越快。每次创建一个新的跳跃表节点的时候,根据幂次定律(越大的数出现的概率越小)随机生成一个介于1~32之间的值作为level数组的大小就是层的高度
  • 前进指针:每个层都一个指向表尾方向的前进指针,用于从表头向表尾方向访问节点
  • 跨度:层的跨度用于记录两个节点之间的距离,跨度是用来计算排位的:在查找某个节点的过程中,将沿途访问过的所有层的跨度累计起来就是目标节点在跳跃表中的排位
  • 后退指针:用于从表尾向表头方向访问节点,后退指针只能后退至前一个节点
  • 分值和成员:跳跃表中的所有节点都是按照分值从小到大来排序。节点的成员对象是一个指针,它指向一个字符串对象。在同一个跳跃表中,各个节点保存的对象必须是唯一的,但是多个节点保存的分值可以是相同的,分值相同的节点将按照成员对象在字典序中大小从小到大进行排序

2、跳跃表的定义

typedef struct zskiplist{struct skiplistNode *header,*tail; //表头节点和表尾节点unsigned long length; //表中节点的数量int level; //表中层数最大的节点的层数
}zskiplist;

  • header和tail指针分别指向跳跃表的表头和表尾节点* length属性记录了节点的数量,表头节点不包含leng
  • length属性记录了节点的数量,表头节点不包含length中* level属性记录了跳跃表中层高最大的那个节点的层数量,表

2.5 整数集合

intset 是集合键的底层实现之一,当一个集合只包含整数,且元素数量不多时,Redis会使用此作为集合键的底层实现。可以保存类型int16_t、int32_t、int64_t的整数值,并且保证集合中不会出现重复元素且是有序的

1、整数集合intset的定义

typedef struct intset{uint32_t encoding; //编码方式uint32_t length; //集合中包含的元素的数量int8_t contents[]; //保存元素的数组,各个项在数组中从小到大有序排序,且不会重复
}zskiplist;

  • contents数组虽然声明为int8_t类型的数组,但实际上真正的类型取决于encoding属性的值
  • 当向一个底层为int16_t数组的整数集合添加一个int64_t类型的整数时,根据整数集合的升级规则整数集合已有的所有元素都会被转换成int64_t类型
  • 整数集合的升级的算法复杂度是O(n)

2、整数集合的升级步骤

  • 根据新元素的类型,扩展整数集合底层数组的空间大小,并为新的元素分配空间
  • 将底层数组现有的所有元素都转换成与新元素相同类型,并将类型转换后的元素放置到准确位置上,放置过程维持有序
  • 将新元素添加到底层数组里面

3、升级的好处

  • 提升灵活性:我们可以随意地将int16_t、int32_t、int64_t类型的整数添加到集合中,不必担心出现类型错误
  • 节约内存:要让一个数组同时保存int16_t、int32_t、int64_t三种类型,最简单的方式是直接使用int64_t类型的数组,但是这样会浪费内存。升级可以让集合既能同时保存三种不同类型的值又可以确保升级操作只会在需要的时候进行。
  • 整数集合不支持降级操作,一旦对数组进行了升级,就有一直保存升级后的状态

2.6 压缩列表ziplist

压缩列表是列表键和哈希键的底层实现之一,当一个列表键或者哈希键包含少量列表项并且每个列表项要么是小整数值要么是长度比较短的字符串,Redis就会使用压缩列表来做列表键的是底层实现。是一种为节约内存而开发的顺序型结构

1、压缩列表的组成

2.3 压缩列表的组成
  • zlbytes:整个压缩列表占用的内存字节数,对压缩列表进行内存重分配或计算zlend时使用
  • zltail:记录列表表尾节点距离起始位置有多少距离
  • zllen:压缩列表包含的节点数量
  • entryX:列表节点
  • zlen:特殊值,用于标记压缩列表的末端

2、压缩列表节点的组成

每个节点可以保存一个字节数组或者整数值

2.4 压缩列表节点的组成
  • previous_entry_length:压缩列表前一个节点的长度,长度可以是一个字节或者五个字节。如果前一个字节的长度小于254字节,那么previous_entry_length属性的长度为1字节,前一个节点的长度就保存在这一个字节里面。如果前一个节点的长度大于等于254,那么previous_entry_length属性的长度为5个字节,第一个字节会被设置为0xFE(十进制254),之后的四个字节用于保存前一个节点的长度。previous_entry_length属性记录了前一个节点的长度,所以程序可以通过指针,算出前一个节点的起始位置。
  • encoding:记录了保存的数据类型以及长度
  • content:保存节点的值

3、连锁更新

在一些特殊情况下,连续多次空间扩展操作称之为连锁更新。连锁更新在最坏情况下需要对压缩列表进行N次空间分配操作,而每次空间分配的最坏的复杂度是O(N)。所以连锁更新的最坏复杂度是O(n^2)

造成连锁更新的概率是很低的,因为压缩列表恰好有多个连续的、长度介于250~253之间的节点,连续更新才有可能被触发,实际情况下出现的概率很低其次,出现连锁更新时,只要被更新的节点数量不多,也不会造成性能问题


2.7 对象

  • 对象包括字符串对象、列表对象、哈希对象、集合对象和有序集合对象五种类型。
  • 使用对象的好处是Redis执行命令之前可以根据对象的类型来判断一个对象是否可以执行给定的命令。
  • 另外更灵活,可以针对不同的场景对对象设置多种不同的数据结构来实现。
  • Redis的对象系统还实现了基于引用计数技术的内存回收机制。当程序不再使用某个对象的时候,这个对象占用的内存会被自动释放。并且通过这种技术实现了对象共享机制,可以节约内存
  • Redis的对象带有访问时间记录信息,该信息可以用于计算数据库键的空转时长,在服务启用了maxmemory功能情况下,空转时长较大的那些键会优先被服务器删除

1、对象的类型与编码

typedef struct redisObject{unsigned type:4;//类型unsigned encoding:4; //编码void *ptr; //指向底层实现数据结构的指针
}robj;

  • 对象的类型
2.5 对象的类型
  • 编码:就是对象使用了什么数据结构作为对象的底层实现
2.6 对象的编码
  • 不同类型对象使用的不同的编码
2.7 不同类型对象不同的编码
  • 通过encoding属性来设定对象所使用的编码,而不是为特定类型的对象关联一种固定的编码,极大地提升了Redis的灵活性和效率,因为Reid可以根据不同的使用场景来为一个对象设置不同的编码,从而优化对象在某一场景下的效率

2、字符串对象

字符串对象的编码可以是intraw或者embstr

  • 如果字符串对象保存的是整数,且这个整数值可以用long类型来表示,则字符串对象编码为int
  • 如果保存的是一个字符串值,并且这个字符串值的长度大于44字节,那么就会使用SDS来保存这个字符串值,编码设置为raw。如果字符串长度小于等于44字节,则会使用embstr。raw会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,而embstr编码则通过调用一次内存分配函数来分配一块连续的空间,空间中一次包含redisObject结构和sdshdr结构
  • double类型的浮点数也是作为字符串值来保存的
  • 编码的转换:对于int编码的字符串对象,向对象执行了命令使得这个对象保存不再是整数值,而是一个字符串值,那么字符串对象的编码将从int变为raw。embstr编码的字符串对象在执行任何修改命令之后,就会变成raw编码的字符串对象。

3、列表对象

列表对象的编码可以是ziplist或者linkedlist

编码转换:满足以下两个条件时,列表对象使用ziplist编码

  • 列表对象保存的所有字符串元素的长度都小于64字节
  • 列表对象保存的元素数量小于512个。不能满足这两个条件的列表对象需要使用linkedlist编码,但是在reids3.2版本以后列表统一底层实现为quicklist

4、哈希对象

哈希对象的编码可以是ziplist或者hashtable

  • 如果是ziplist,先将键推入压缩列表的表尾,再将值推入压缩列表的表尾,同一键值对的两个节点总是挨着的,且键在前值在后。另外,先加入的键值对放在压缩列表的表头方向,后加入的添加到表尾方向。
  • hashtable编码的哈希对象中每个点只对都是使用一个字典键值对来保存

编码转换:满足以下两个条件会使用ziplist

  • 哈希对象保存的所有键值对的键和值的字符串长度都小于64
  • 哈希对象保存的键值对数量小于512个

5、集合对象

集合对象的编码可以是intset或者hashtable。当使用hashtable作为底层实现,字典的每个键都是一个包含一个集合元素的字符串对象,而每个值都为null

编码转换:满足以下两个条件会使用intset

  • 集合对象保存的所有元素都是整数值
  • 集合对象保存的所有元素的数量不超过512个

6、有序集合对象

有序集合对象的编码可以是ziplist或者skiplist。使用ziplist编码的压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点保存,第一个节点保存元素的成员(member),第二个节点保存元素的分值(score)。当使用skiplist编码的有序集合对象使用zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃表。跳跃表每个节点的object属性保存了元素的成员,score属性保存了元素的分值。字典则是保存了成员和分值的映射,字典的键保存了元素的成员,值保存了相应的分值。这样可以用O(1)的复杂度查找指定元素的分值。另外,这两种数据结构都会通过指针共享相同元素的成员和分值,所以不会浪费额外的内存。

编码转换:满足以下两个条件会使用ziplist

  • 有序集合保存的元素数量小于128个
  • 有序集合保存的所有元素成员的长度都小于64字节

7、类型检查与命令多态

Redis操作键的命令基本上分为两种,一种是可以对任何类型的键执行,比如del、expire、rename、type、object等命令。另一种是只能对特定类型的键执行,比如

  • SET、GET、APPEND、STRLEN等只能用于字符串键
  • HDEL、HSET、HGET、HLEN等命令只能对哈希键执行
  • RPUSH、LPOP、LINSERT、LLEN等命令只能对列表键执行
  • SADD、SPOP、SINTER、SCARD等命令只能对集合键执行
  • ZADD、ZCARD、ZRANK、ZSCORE等命令只能对有序集合执行

7.1 类型检查的实现

类型检查是为了确保只有指定类型的键可以执行某些特定的命令,是通过redisObject结构的type属性来实现的。

7.2 多态命令的实现

根据值对象的编码方式,选择正确的命令实现代码来执行命令。像del、expire、type等命令式基于类型的多态,一个命令可以同时处理多种不同类型的键。SET、LLEN等命令是基于编码类型的多态,一个命令可以同时处理不同的编码

2.8 多态命令的实现

7.3 内存回收

redis通过构建了一个引用计数技术实现的内存回收机制。每个对象的引用计数信息保存在redisObject结构的refcount属性。当创建一个新对象时,引用计数的值会初始化为1;当对象被新的程序使用时,它的引用过计数值会被增1;当对象不再被一个程序使用时,它的引用计数值会被减一;当对象的引用计数变为0时,对象所占用的内存会被释放。

7.4 对象共享

实现原理也是使用对的引用计数属性。让多个键共享同一个值对象只要把键的值指针指向一个现有的值对象,并且把被共享的值对象的引用计数增一。Redis只对包含整数值的字符串对象进行共享。

7.5 对象的空转时长

redisObject最后一个属性lru记录了对象最后一次被命令程序访问的时间。当服务器占用的内存数超过了maxmemory选项所设置的上限值时,空转时长较高的那部分键会优先被服务器释放掉,从而回收内存。

总结

  • Redis数据库中的每个键值对的键和值都是一个对象
  • Redis共有字符串、列表、哈希、集合、有序集合五种类型的对象,每种类型的对象至少都有两种或以上的编码方式,不同的编码可以在不同的使用场景下优化对象的使用效率
  • Redis的对象系统带有引用计数实现的内存回收机制,当一个对象不再被使用时,该对象所占用的内存就会被自动释放
  • Redis会共享值为0到9999的字符串对象
  • 对象会记录自己的最后一次被访问的时间,这个时间可以用于计算对象的空转时间

redis五种数据类型的应用场景_Redis五种不同的数据类型相关推荐

  1. hashmap应用场景_Redis 5种数据结构 及使用场景分析

    也当过面试官,面试过不少应聘者,因为是我自己招人自己用,所以我不会看应聘者造火箭的技术有多牛比,只看拧螺丝的手艺瓷不瓷实.毕竟以后是一个整体,拖了大家后腿团队都很难受. 面试的题目一般也不会太难,就像 ...

  2. mysql两种引擎的适用场景_MySQL两种引擎的区别和应用场景

    Innodb引擎 Innodb引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别.该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它本身其实就是基于MySQL ...

  3. Redis 数据类型及应用场景

    一. redis 特点 所有数据存储在内存中,高速读写 提供丰富多样的数据类型:string. hash. set. sorted set.bitmap.hyperloglog 提供了 AOF 和 R ...

  4. 固定编辑框输入上限和下限_两种截然不同的汉字输入场景

    汉字输入法有两种截然不同的应用场景,一种是大众应用,另一种是专业应用.所谓大众应用,是指一般的人使用汉字输入法来满足日常的工作和生活需要,比如写作.聊天等.所谓专业应用,是指打字员.参与打字比赛的人等 ...

  5. Redis五种数据类型及应用场景

    Redis五种数据类型及应用场景 MySql+Memcached架构的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样 ...

  6. Redis的五种数据类型及应用场景

    1,数据类型 String(字符串,整数,浮点数):做简单的键值对缓存 List(列表):储存一些列表类型的数据结构 Set(无序集合):交集,并集,差集的操作 Hash(包含键值对的无序散列表):结 ...

  7. Redis的数据类型以及每种数据类型的使用场景

    人就是很奇怪的动物,很简单的问题往往大家都容易忽略,当我们在使用分布式缓存Redis的时候,一个最简单的问题往往被人忽略,Redis的数据类型以及每种数据类型的使用场景是什么? 是不是觉得这个问题很基 ...

  8. formdata.append加多个值_redis的五种数据结构和应用场景:微博微信点赞+加购物车等...

    Redis五种数据结构如下: 1.String 字符串类型 是redis中最基本的数据类型,一个key对应一个value. String类型是二进制安全的,意思是 redis 的 string 可以包 ...

  9. 2 万字 + 20张图| 细说 Redis 九种数据类型和应用场景

    作者:小林coding 计算机八股文网(操作系统.计算机网络.计算机组成.MySQL.Redis):https://xiaolincoding.com 大家好,我是小林. 我们都知道 Redis 提供 ...

最新文章

  1. Spring BeanFactory与FactoryBean的区别及其各自的详细介绍于用法
  2. 麻省理工学院开发出可“听音识貌”的人工智能
  3. 谁说菜鸟不会数据分析python下载_刻意练习9:《谁说菜鸟不会数据分析python篇》第3章编程基础总计46页学习笔记...
  4. jmeter接口测试----9函数助手: random, counter, time
  5. Apollo进阶课程 ② | 开源模块讲解(上)
  6. 利用循环队列的思想进行加密解密(洛谷P1914题题解,Java语言描述)
  7. Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine
  8. iOS中事件的传递和响应者链条
  9. 数据科学之:消费者资产分析
  10. html 父模板,详解vue父子模版嵌套案例
  11. NTC功率型热敏电阻
  12. ThinkPad E431 Bluetooth驱动
  13. 小学信息技术 用计算机画画 教学目标,小学信息技术教学计划
  14. 支配节点树及其构建算法 Dominator-tree and its Construction Algorithms
  15. 现有列表记录商品名称和价格如下:‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬要求用户输入总资产,例如: 20000,输出所有商品序号和商品列表,每行
  16. coldfusion_ColdFusion中的一周:1月30日至2月5日:一切
  17. 美通企业日报 | 麦德龙在重庆开第4家店;假日品牌在华第100家酒店开业
  18. linux 搭建 MeepoPS+Socket
  19. SaaS/大数据2019十大新闻出炉:我们不是“孤胆英雄”!
  20. 层次结构工程命名建议

热门文章

  1. MySQL修改字段的排列位置
  2. easyUI的目录结构
  3. Python按键精灵自动化_安装Python
  4. RocketMQ主机磁盘空间有限,如何无限期延长消息存储?
  5. 硬核!一套基于SpringBoot + Vue 的开源物联网智能家居系统!
  6. 为什么大厂都用DevOps呢?我来告诉你
  7. vs2013下oracle proc配置
  8. Hibernate核心配置文件cfg参数说明
  9. JavaWeb开发模式:C/S模式,B/S模式,JSP+JavaBean模式,JSP+Servlet+JavaBean模式
  10. .net 数字转汉字_[原创工具] 小熊汉字笔顺学习软件,查笔顺、学拼音、制作汉字英文数字字贴...