Redis

一、NoSQL概述

泛指非关系型的数据库,可以解决三高问题:

  • 对数据库高并发的读写需求
  • 对海量数据的高效存储和访问的需求
  • 对数据库的高扩展性和高可用性的需求

NoSQL数据库的四大分类:

  • 键值对存储(key-value)数据库
相关产品:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB
典型应用:内容缓存,主要用于处理大量数据的高访问负载
数据模型:一系列键值对,主要会使用到一个 哈希表,这个表中有一个特定的键和一个指针指向特定的数据
  •  列存储(Wide Column Store/Column-Family)数据库

相关产品:Cassandra, HBase, Riak
典型应用:分布式的文件系统
数据模型:列存储数据库将数据储存在列族(column family)中,一个列族存储经常被一起查询的相关数据
  •  面向文档(Document-Oriented)数据库

相关产品:CouchDB, MongoDb,SequoiaDB
典型应用:Web应用
数据模型:也是一系列键值对,面向文档数据库会将数据以文档的形式储存。每个文档都是自包含的数据单元,是一系列数据项的集合。每个数据项都有一个名称与对应的值,值既可以是简单的数据类型,如字符串、数字和日期等;也可以是复杂的类型,如有序列表和关联对象。数据存储的最小单位是文档,同一个表中存储的文档属性可以是不同的,数据可以使用XML、JSON或者JSONB等多种形式存储。

  • 图(Graph-Oriented)数据库

相关产品:Adobe (Neo4J)、Cisco (Neo4J)、T-Mobile (Neo4J)

典型应用:社交网络

数据模型:图结构,允许我们将数据以图的方式储存。实体会被作为顶点,而实体之间的关系则会被作为边


二、Redis概述

Redis是用C语言开发的一个开源的高性能键值对数据库,它通过提供多种键值数据类型来适应不同场景的存储需求。一个Redis实例可以包括多个数据库,客户端可以指定连接某个redis实例的哪个数据库,就好比一个mysql中创建多个数据库,客户端连接时指定连接哪个数据库。一个redis实例最多可提供16个数据库。

redis使用了两种文件格式:全量数据和增量请求。

  • 全量数据格式是把内存中的数据写入磁盘,便于下次读取文件进行加载。
  • 增量请求文件则是把内存中的数据序列化为操作请求,用于读取文件进行replay得到数据,序列化的操作包括SET、RPUSH、SADD、ZADD。
redis的存储分为内存存储、磁盘存储和log文件三部分,配置文件中有三个参数对其进行配置。

关于key的定义呢,需要大家注意的几点:
  • key不要太长,最好不要操作1024个字节,这不仅会消耗内存还会降低查找效率
  • key不要太短,如果太短会降低key的可读性
  • 在项目中,key最好有一个统一的命名规范

三、数据类型

1、string(字符串):

string是最简单的类型,一个key对应一个value,源文件sds.h/sds.c。

字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等。在Redis中字符串类型的Value最多可以容纳的数据长度是512M。

2、list(双向链表):

list是一个链表结构,主要功能是push、pop、获取一个范围的所有值等等。操作中key理解为链表的名字,源文件adlist.h/adlist.c。

在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。从元素插入和删除的效率视角来看,如果我们是在链表的两头插入或删除元素,这将会是非常高效的操作,即使链表中已经存储了百万条记录,该操作也可以在常量时间内完成。然而需要说明的是,如果元素插入或删除操作是作用于链表中间,那将会是非常低效的。
  • ArrayList使用数组方式存储数据,所以根据索引查询数据速度快,而新增或者删除元素时需要设计到位移操作,所以比较慢。
  • LinkedList使用双向链接方式存储数据,每个元素都记录前后元素的指针,所以插入、删除数据时只是更改前后元素的指针指向即可,速度非常快,然后通过下标查询元素时需要从头开始索引,所以比较慢。
Redis链表经常会被用于消息队列的服务,以完成多程序之间的消息交换。

3、dict(hash表):

Redis中的Hashes类型可以看成具有String Key和String Value的map容器。所以该类型非常适合于存储值对象的信息。如Username、Password和Age等。如果Hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。

4、set:

set是集合,和我们数学中的集合概念相似,对集合的操作有添加删除元素,有对多个集合求交并差等操作。操作中key理解为集合的名,源文件dict.h/dict.c。

在Redis中,我们可以将Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。需要说明的是,这些操作的时间复杂度为O(1),即常量时间内完成次操作。Set集合中不允许出现重复的元素。

  • 可以使用Redis的Set数据类型跟踪一些唯一性数据,比如访问某一博客的唯一IP地址信息。对于此场景,我们仅需在每次访问该博客时将访问者的IP存入Redis中,Set数据类型会自动保证IP地址的唯一性。
  • 充分利用Set类型的服务端聚合操作方便、高效的特性,可以用于维护数据对象之间的关联关系。比如所有购买某一电子设备的客户ID被存储在一个指定的Set中,而购买另外一种电子产品的客户ID被存储在另外一个Set中,如果此时我们想获取有哪些客户同时购买了这两种商品时,Set的intersections命令就可以充分发挥它的方便和效率的优势了。

5、sortedset:

是set的一个升级版本,他在set的基础上增加了一个顺序属性,这一属性在添加修改元素的时候可以指定,每次指定后,zset会自动重新按新的值调整顺序。可以理解了有两列的mysql表,一列存value,一列存顺序。操作中key理解为zset的名字。

  • 可以用于一个大型在线游戏的积分排行榜。每当玩家的分数发生变化时,可以执行ZADD命令更新玩家的分数,此后再通过ZRANGE命令获取积分TOPTEN的用户信息。当然我们也可以利用ZRANK命令通过username来获取玩家的排行信息。最后我们将组合使用ZRANGE和ZRANK命令快速的获取和某个玩家积分相近的其他用户的信息。
  • 还可用于构建索引数据。

四、Redis电商应用场景

  • 各种计数,商品维度计数和用户维度计数

Redis的命令都是原子性的,你可以轻松地利用INCR,DECR等命令来计数。

  • 存储社交关系

譬如将用戶的好友/粉丝/关注,可以存在一个sorted set中,score可以是timestamp,这样求两个人的共同好友的操作,可能就只需要用求交集命令即可。

  • 用作缓存代替memcached(商品列表,评论列表,@提示列表,etc)
相对memcached 简单的key-value存储来说,redis众多的数据结构(list,set,sorted set,hash, etc)可以更方便cache各种业务数据,性能也不亚于memcached。
  • 最新列表&排行榜(用户刚刚喜欢的商品,etc)
这里采用Redis的List数据结构或sorted set 结构, 方便实现最新列表or排行榜 等业务场景。

五、Redis持久化

1、RDB持久化(默认支持,无需配置)

该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。
  • 优势
    1. 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
    2. 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上
    3. 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
    4. 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。
  • 劣势
    1. 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
    2. 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟

2、AOF持久化

该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。
  • 优势
    1. 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
    2. 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
    3. 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
    4. 4AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
  • 劣势
  1. 对于相同数量的数据集而言,AOF文件通常要大于RDB文件
  2. 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。

3、无持久化

我们可以通过配置的方式禁用Redis服务器的持久化功能,这样我们就可以将Redis视为一个功能加强版的memcached了。

4、redis同时使用RDB和AOF

六、redis集群

1、原理

架构细节:
  1. 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
  2. 节点的fail是通过集群中超过半数的节点检测失效时才生效.
  3. 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
  4. redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
redis集群的好处:将数据分散在不同的节点上,降低单个节点的吞吐量,从而提高单个节点的性能。

2、投票容错

(1)领着投票过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉.
(2)什么时候整个集群不可用(cluster_state:fail)? 
  •     如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完成时进入fail状态. ps : redis-3.0.0.rc1加入cluster-require-full-coverage参数,默认关闭,打开集群兼容部分失败。
  •     如果集群超过半数以上master挂掉,无论是否有slave集群进入fail状态。
(3)当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误

七、复制原理和配置参数

Redis使用的是master-slave主从复制模式,从2.8版本开始,这个过程是异步的。


1. 工作原理


当一个slave首次或重新连接到master的时候,会向master发送一个PSYNC命令(2.8版本之前是SYNC命令)要求同步数据。


1.1 全量同步 Full resynchronization


当master接收到slave的同步命令之后会执行BGSAVE启动一个background进程创建.rdb持久化文件,同时会将所有新执行的写入命令都保存到一个缓冲区里面。当.rdb保存完毕之后,master会把.rdb文件传送给slave,然后slave会把保存的.rdb文件load到内存里面,最后master会将缓冲区里面的所有写命令发送给slave。如果master接收到多个slave的同步请求,master只会执行一次BGSAVE命令,然后把保存的.rdb文件同时传送给所有的slave(占用较多的资源和带宽)。当master-slave的连接由于某种原因断开时,slave会自动重新连接。在2.8版本之前,断线后的重新连接是会执行全量同步,在2.8版本开始,slave是可以根据master的情况来自动选择执行全量同步还是增量同步(partial resynchronization)。


1.2 增量同步 Partial resynchronization


从2.8版本开始,Redis在master端创建了一个复制流的内存缓冲区,master和所有slave都标记一个复制的偏移量和master runid,用于当master-slave连接短暂断开然后重新连接的时候,master和slave可以执行增量同步,也就是从之前断开的部分开始同步,而不需要执行全量同步。前提条件是master runid和之前是相同的,并且标记的复制偏移量仍然在复制流的内存缓冲区里面,否则的话会执行全量同步。这种新的增量同步特性会使用PSYNC命令,而2.8版本之前会使用SYNC命令。值得注意的是,如果slave是2.8或以上的版本能够检测master是否支持PSYNC命令,如果不支持会自动使用SYNC命令。


2. 无盘复制 Diskless replication


从2.8.18版本开始支持无盘复制,master以流的方式直接传送数据给slave,不需要创建.rdb文件,slave接收数据后仍然会保存.rdb文件然后load到内存里面。这种选项的优点就是避免master的磁盘读写慢导致的性能问题。


3. Replication的配置


Redis的复制有3种配置方式:


3.1 在slave的配置文件redis.conf里面添加slaveof <masterip> <masterport>,masterip是master的ip,masterport是master的端口

3.2 在使用redis-server启动slave的时候,直接添加--slaveof <masterip> <masterport>参数(非配置文件启动方式)

3.3 使用redis-cli连接slave,然后执行slaveof <masterip> <masterport>命令


4. slave端的相关配置


slave-read-only yes #从2.6版本开始支持只读的slave,默认是yes的


masterauth <master-password> #如果master配置了requirepass设置密码,slave需要配置连接master的密码


slave-serve-stale-data yes #当slave与master断开或者复制正在进行的时候是否继续提供服务,默认是yes继续服务,可以配置为no返回错误提示“SYNC with master in progress”(除了INFO和SLAVEOF命令)


repl-ping-slave-period 10 #slave发送心跳的间隔时间,默认是10秒


5. master端的相关配置


repl-diskless-sync no #是否使用无盘复制 Diskless replication,默认是no


repl-diskless-sync-delay 5 #无盘复制延时开始秒数,默认是5秒,意思是当PSYNC触发的时候,master延时多少秒开始向master传送数据流,以便等待更多的slave连接可以同时传送数据流,因为一旦PSYNC开始后,如果有新的slave连接master,只能等待下次PSYNC。可以配置为0取消等待,立即开始


repl-backlog-size 1mb #复制流的内存缓冲区大小,用于增量同步,当master-slave断开的时候,master保存在复制流内存缓冲区的数据大小限制,默认是1mb。如果至少有1个slave连接的话,就会释放


repl-backlog-ttl 3600 #复制流的内存缓冲区过时时间,默认3600秒,就是说无论保存在复制流内存缓冲区的数据大小是否超过限制,当master-slave断开超过上述时间就会释放


min-slaves-to-write 3 #从2.8版本开始,可以配置与master连接的slave的最少数量,默认是0没有限制,如果配置>0,需要结合下面的选项一起使用,只有同时满足这2个选项,master才能接收写操作


min-slaves-max-lag 10 #允许master-slave的心跳最大间隔,默认是10秒,需要结合min-slaves-to-write选项一起使用

6. 复制+持久化的数据完整性考虑


如果master配置了slave,那么强烈建议master启用持久化。因为当master重启的时候,如果没有启用持久化,数据会全部丢失,而且当slave重新连接master的时候,slave原有的数据也会被清空。如果真的要配置不启用持久化,最好不要设置自动启动master,除非数据全部丢失对你来说不重要。

八、附录

一、String所有命令

1、相关命令列表说明:

命令原型
时间复杂度 命令描述 返回值
APPEND key value 如果该Key已经存在,APPEND命令将参数Value的数据追加到已存在Value的末尾。如果该Key不存在,APPEND命令将会创建一个新的Key/Value。 追加后Value的长度。
DECR key 将指定Key的Value原子性的递减1。如果该Key不存在,其初始值为0,在decr之后其值为-1。如果Value的值不能转换为整型值,如Hello,该操作将执行失败并返回相应的错误信息。注意:该操作的取值范围是64位有符号整型。 递减后的Value值。
INCR key 将指定Key的Value原子性的递增1。如果该Key不存在,其初始值为0,在incr之后其值为1。如果Value的值不能转换为整型值,如Hello,该操作将执行失败并返回相应的错误信息。注意:该操作的取值范围是64位有符号整型。 递增后的Value值。
DECRBY key decrement 将指定Key的Value原子性的减少decrement。如果该Key不存在,其初始值为0,在decrby之后其值为-decrement。如果Value的值不能转换为整型值,如Hello,该操作将执行失败并返回相应的错误信息。注意:该操作的取值范围是64位有符号整型。 减少后的Value值。
INCRBY key increment 将指定Key的Value原子性的增加increment。如果该Key不存在,其初始值为0,在incrby之后其值为increment。如果Value的值不能转换为整型值,如Hello,该操作将执行失败并返回相应的错误信息。注意:该操作的取值范围是64位有符号整型。 增加后的Value值。
GET key 获取指定Key的Value。如果与该Key关联的Value不是string类型,Redis将返回错误信息,因为GET命令只能用于获取string Value。 与该Key相关的Value,如果该Key不存在,返回nil。
SET key value
设定该Key持有指定的字符串Value,如果该Key已经存在,则覆盖其原有值。 总是返回"OK"。
GETSET key value 原子性的设置该Key为指定的Value,同时返回该Key的原有值。和GET命令一样,该命令也只能处理string Value,否则Redis将给出相关的错误信息。 返回该Key的原有值,如果该Key之前并不存在,则返回nil。
STRLEN key 返回指定Key的字符值长度,如果Value不是string类型,Redis将执行失败并给出相关的错误信息。 返回指定Key的Value字符长度,如果该Key不存在,返回0。
SETEX key seconds value 原子性完成两个操作,一是设置该Key的值为指定字符串,同时设置该Key在Redis服务器中的存活时间(秒数)。该命令主要应用于Redis被当做Cache服务器使用时。
(expire)
SETNX key value 如果指定的Key不存在,则设定该Key持有指定字符串Value,此时其效果等价于SET命令。相反,如果该Key已经存在,该命令将不做任何操作并返回。 1表示设置成功,否则0。
(not exists)

SETRANGE key offset value 替换指定Key的部分字符串值。从offset开始,替换的长度为该命令第三个参数value的字符串长度,其中如果offset的值大于该Key的原有值Value的字符串长度,Redis将会在Value的后面补齐(offset - strlen(value))数量的0x00,之后再追加新值。如果该键不存在,该命令会将其原值的长度假设为0,并在其后添补offset个0x00后再追加新值。鉴于字符串Value的最大长度为512M,因此offset的最大值为536870911。最后需要注意的是,如果该命令在执行时致使指定Key的原有值长度增加,这将会导致Redis重新分配足够的内存以容纳替换后的全部字符串,因此就会带来一定的性能折损。 修改后的字符串Value长度。
GETRANGE key start end 如果截取的字符串长度很短,我们可以该命令的时间复杂度视为O(1),否则就是O(N),这里N表示截取的子字符串长度。该命令在截取子字符串时,将以闭区间的方式同时包含start(0表示第一个字符)和end所在的字符,如果end值超过Value的字符长度,该命令将只是截取从start开始之后所有的字符数据。 子字符串
取整个字符串,可以将start和end定为 0 , -1

SETBIT key offset value 设置在指定Offset上BIT的值,该值只能为1或0,在设定后该命令返回该Offset上原有的BIT值。如果指定Key不存在,该命令将创建一个新值,并在指定的Offset上设定参数中的BIT值。如果Offset大于Value的字符长度,Redis将拉长Value值并在指定Offset上设置参数中的BIT值,中间添加的BIT值为0。最后需要说明的是Offset值必须大于0。 在指定Offset上的BIT原有值。
GETBIT key offset 返回在指定Offset上BIT的值,0或1。如果Offset超过string value的长度,该命令将返回0,所以对于空字符串始终返回0。 在指定Offset上的BIT值。
(布隆过滤器)

MGET key [key ...] 返回所有指定Keys的Values,如果其中某个Key不存在,或者其值不为string类型,该Key的Value将返回nil。 返回一组指定Keys的Values的列表。
MSET key value [key value ...] 该命令原子性的完成参数中所有key/value的设置操作,其具体行为可以看成是多次迭代执行SET命令。 该命令不会失败,始终返回OK。
MSETNX key value [key value ...] 该命令原子性的完成参数中所有key/value的设置操作,其具体行为可以看成是多次迭代执行SETNX命令。然而这里需要明确说明的是,如果在这一批Keys中有任意一个Key已经存在了,那么该操作将全部回滚,即所有的修改都不会生效。 1表示所有Keys都设置成功,0则表示没有任何Key被修改。

2、命令示例:

1). SET/GET/APPEND/STRLEN:

/> redis-cli #执行Redis客户端工具。
redis 127.0.0.1:6379> exists mykey #判断该键是否存在,存在返回1,否则返回0。
(integer) 0
redis 127.0.0.1:6379> append mykey "hello" #该键并不存在,因此append命令返回当前Value的长度。
(integer) 5
redis 127.0.0.1:6379> append mykey " world" #该键已经存在,因此返回追加后Value的长度。
(integer) 11
redis 127.0.0.1:6379> get mykey #通过get命令获取该键,以判断append的结果。
"hello world"
redis 127.0.0.1:6379> set mykey "this is a test" #通过set命令为键设置新值,并覆盖原有值。
OK
redis 127.0.0.1:6379> get mykey
"this is a test"
redis 127.0.0.1:6379> strlen mykey #获取指定Key的字符长度,等效于C库中strlen函数。
(integer) 14

2). INCR/DECR/INCRBY/DECRBY:

redis 127.0.0.1:6379> set mykey 20 #设置Key的值为20
OK
redis 127.0.0.1:6379> incr mykey #该Key的值递增1
(integer) 21
redis 127.0.0.1:6379> decr mykey #该Key的值递减1
(integer) 20
redis 127.0.0.1:6379> del mykey #删除已有键。
(integer) 1
redis 127.0.0.1:6379> decr mykey #对空值执行递减操作,其原值被设定为0,递减后的值为-1
(integer) -1
redis 127.0.0.1:6379> del mykey
(integer) 1
redis 127.0.0.1:6379> incr mykey #对空值执行递增操作,其原值被设定为0,递增后的值为1
(integer) 1
redis 127.0.0.1:6379> set mykey hello #将该键的Value设置为不能转换为整型的普通字符串。
OK
redis 127.0.0.1:6379> incr mykey #在该键上再次执行递增操作时,Redis将报告错误信息。
(error) ERR value is not an integer or out of range
redis 127.0.0.1:6379> set mykey 10
OK
redis 127.0.0.1:6379> decrby mykey 5
(integer) 5
redis 127.0.0.1:6379> incrby mykey 10
(integer) 15

3). GETSET:

redis 127.0.0.1:6379> incr mycounter #将计数器的值原子性的递增1
(integer) 1
#在获取计数器原有值的同时,并将其设置为新值,这两个操作原子性的同时完成。
redis 127.0.0.1:6379> getset mycounter 0
"1"
redis 127.0.0.1:6379> get mycounter #查看设置后的结果。
"0"

4). SETEX:

redis 127.0.0.1:6379> setex mykey 10 "hello" #设置指定Key的过期时间为10秒。
OK
#通过ttl命令查看一下指定Key的剩余存活时间(秒数),0表示已经过期,-1表示永不过期。
redis 127.0.0.1:6379> ttl mykey
(integer) 4
redis 127.0.0.1:6379> get mykey #在该键的存活期内我们仍然可以获取到它的Value。
"hello"
redis 127.0.0.1:6379> ttl mykey #该ttl命令的返回值显示,该Key已经过期。
(integer) 0
redis 127.0.0.1:6379> get mykey #获取已过期的Key将返回nil。
(nil)

5). SETNX:

redis 127.0.0.1:6379> del mykey #删除该键,以便于下面的测试验证。
(integer) 1
redis 127.0.0.1:6379> setnx mykey "hello" #该键并不存在,因此该命令执行成功。
(integer) 1
redis 127.0.0.1:6379> setnx mykey "world" #该键已经存在,因此本次设置没有产生任何效果。
(integer) 0
redis 127.0.0.1:6379> get mykey #从结果可以看出,返回的值仍为第一次设置的值。
"hello"

6). SETRANGE/GETRANGE:

redis 127.0.0.1:6379> set mykey "hello world" #设定初始值。
OK
redis 127.0.0.1:6379> setrange mykey 6 dd #从第六个字节开始替换2个字节(dd只有2个字节)
(integer) 11
redis 127.0.0.1:6379> get mykey #查看替换后的值。
"hello ddrld"
redis 127.0.0.1:6379> setrange mykey 20 dd #offset已经超过该Key原有值的长度了,该命令将会在末尾补0。
(integer) 22
redis 127.0.0.1:6379> get mykey #查看补0后替换的结果。
"hello ddrld\x00\x00\x00\x00\x00\x00\x00\x00\x00dd"
redis 127.0.0.1:6379> del mykey #删除该Key。
(integer) 1
redis 127.0.0.1:6379> setrange mykey 2 dd #替换空值。
(integer) 4
redis 127.0.0.1:6379> get mykey #查看替换空值后的结果。
"\x00\x00dd"
redis 127.0.0.1:6379> set mykey "0123456789" #设置新值。
OK
redis 127.0.0.1:6379> getrange mykey 1 2 #截取该键的Value,从第一个字节开始,到第二个字节结束。
"12"
redis 127.0.0.1:6379> getrange mykey 1 20 #20已经超过Value的总长度,因此将截取第一个字节后面的所有字节。
"123456789"

7). SETBIT/GETBIT:

redis 127.0.0.1:6379> del mykey
(integer) 1
redis 127.0.0.1:6379> setbit mykey 7 1 #设置从0开始计算的第七位BIT值为1,返回原有BIT值0
(integer) 0
redis 127.0.0.1:6379> get mykey #获取设置的结果,二进制的0000 0001的十六进制值为0x01
"\x01"
redis 127.0.0.1:6379> setbit mykey 6 1 #设置从0开始计算的第六位BIT值为1,返回原有BIT值0
(integer) 0
redis 127.0.0.1:6379> get mykey #获取设置的结果,二进制的0000 0011的十六进制值为0x03
"\x03"
redis 127.0.0.1:6379> getbit mykey 6 #返回了指定Offset的BIT值。
(integer) 1
redis 127.0.0.1:6379> getbit mykey 10 #Offset已经超出了value的长度,因此返回0。
(integer) 0

8). MSET/MGET/MSETNX:

redis 127.0.0.1:6379> mset key1 "hello" key2 "world" #批量设置了key1和key2两个键。
OK
redis 127.0.0.1:6379> mget key1 key2 #批量获取了key1和key2两个键的值。
1) "hello"
2) "world"
#批量设置了key3和key4两个键,因为之前他们并不存在,所以该命令执行成功并返回1。
redis 127.0.0.1:6379> msetnx key3 "stephen" key4 "liu"
(integer) 1
redis 127.0.0.1:6379> mget key3 key4
1) "stephen"
2) "liu"
#批量设置了key3和key5两个键,但是key3已经存在,所以该命令执行失败并返回0。
redis 127.0.0.1:6379> msetnx key3 "hello" key5 "world"
(integer) 0
#批量获取key3和key5,由于key5没有设置成功,所以返回nil。
redis 127.0.0.1:6379> mget key3 key5
1) "stephen"
2) (nil)

二、list所有命令

1、相关命令列表说明:


命令原型 时间复杂度 命令描述 返回值
LPUSH key value [value ...] 在指定Key所关联的List Value的头部插入参数中给出的所有Values。如果该Key不存在,该命令将在插入之前创建一个与该Key关联的空链表,之后再将数据从链表的头部插入。如果该键的Value不是链表类型,该命令将返回相关的错误信息。 插入后链表中元素的数量。
LPUSHX key value 仅有当参数中指定的Key存在时,该命令才会在其所关联的List Value的头部插入参数中给出的Value,否则将不会有任何操作发生。 插入后链表中元素的数量。
LRANGE key start stop 该命令的参数start和end都是0-based。即0表示链表头部(leftmost)的第一个元素。其中start的值也可以为负值,-1将表示链表中的最后一个元素,即尾部元素,-2表示倒数第二个并以此类推。该命令在获取元素时,start和end位置上的元素也会被取出。如果start的值大于链表中元素的数量,空链表将会被返回。如果end的值大于元素的数量,该命令则获取从start(包括start)开始,链表中剩余的所有元素。 返回指定范围内元素的列表。
LPOP key 返回并弹出指定Key关联的链表中的第一个元素,即头部元素,。如果该Key不存,返回nil。 链表头部的元素。
LLEN key 返回指定Key关联的链表中元素的数量,如果该Key不存在,则返回0。如果与该Key关联的Value的类型不是链表,则返回相关的错误信息。 链表中元素的数量。

LREM key count value 在指定Key关联的链表中,删除前count个值等于value的元素。如果count大于0,从头向尾遍历并删除,如果count小于0,则从尾向头遍历并删除。如果count等于0,则删除链表中所有等于value的元素。如果指定的Key不存在,则直接返回0。 返回被删除的元素数量。
LSET key index value 设定链表中指定位置的值为新值,其中0表示第一个元素,即头部元素,-1表示尾部元素。如果索引值Index超出了链表中元素的数量范围,该命令将返回相关的错误信息。
(对指定脚标的值进行设置)
LINDEX key index 该命令将返回链表中指定位置(index)的元素,index是0-based,表示头部元素,如果index为-1,表示尾部元素。如果与该Key关联的不是链表,该命令将返回相关的错误信息。 返回请求的元素,如果index超出范围,则返回nil。
(读出指定脚标的值)
LTRIM key start stop 该命令将仅保留指定范围内的元素,从而保证链接中的元素数量相对恒定。start和stop参数都是0-based,0表示头部元素。和其他命令一样,start和stop也可以为负值,-1表示尾部元素。如果start大于链表的尾部,或start大于stop,该命令不错报错,而是返回一个空的链表,与此同时该Key也将被删除。如果stop大于元素的数量,则保留从start开始剩余的所有元素。
LINSERT key BEFORE|AFTER pivot value 该命令的功能是在pivot元素的前面或后面插入参数中的元素value。如果Key不存在,该命令将不执行任何操作。如果与Key关联的Value类型不是链表,相关的错误信息将被返回。 成功插入后链表中元素的数量,如果没有找到pivot,返回-1,如果key不存在,返回0。
(在指定的某个value前或后插入一个新的value)

RPUSH key value [value ...] 在指定Key所关联的List Value的尾部插入参数中给出的所有Values。如果该Key不存在,该命令将在插入之前创建一个与该Key关联的空链表,之后再将数据从链表的尾部插入。如果该键的Value不是链表类型,该命令将返回相关的错误信息。 插入后链表中元素的数量。
RPUSHX key value 仅有当参数中指定的Key存在时,该命令才会在其所关联的List Value的尾部插入参数中给出的Value,否则将不会有任何操作发生。 插入后链表中元素的数量。
RPOP key 返回并弹出指定Key关联的链表中的最后一个元素,即尾部元素,。如果该Key不存,返回nil。 链表尾部的元素。
RPOPLPUSH source destination 原子性的从与source键关联的链表尾部弹出一个元素,同时再将弹出的元素插入到与destination键关联的链表的头部。如果source键不存在,该命令将返回nil,同时不再做任何其它的操作了。如果source和destination是同一个键,则相当于原子性的将其关联链表中的尾部元素移到该链表的头部。 返回弹出和插入的元素。

2、命令示例:


1). LPUSH/LPUSHX/LRANGE:

/> redis-cli #在Shell提示符下启动redis客户端工具。
redis 127.0.0.1:6379> del mykey
(integer) 1
#mykey键并不存在,该命令会创建该键及与其关联的List,之后在将参数中的values从左到右依次插入。
redis 127.0.0.1:6379> lpush mykey a b c d
(integer) 4
#取从位置0开始到位置2结束的3个元素。
redis 127.0.0.1:6379> lrange mykey 0 2
1) "d"
2) "c"
3) "b"
#取链表中的全部元素,其中0表示第一个元素,-1表示最后一个元素。
redis 127.0.0.1:6379> lrange mykey 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
#mykey2键此时并不存在,因此该命令将不会进行任何操作,其返回值为0。
redis 127.0.0.1:6379> lpushx mykey2 e
(integer) 0
#可以看到mykey2没有关联任何List Value。
redis 127.0.0.1:6379> lrange mykey2 0 -1
(empty list or set)
#mykey键此时已经存在,所以该命令插入成功,并返回链表中当前元素的数量。
redis 127.0.0.1:6379> lpushx mykey e
(integer) 5
#获取该键的List Value的头部元素。
redis 127.0.0.1:6379> lrange mykey 0 0
1) "e"

2). LPOP/LLEN:

redis 127.0.0.1:6379> lpush mykey a b c d
(integer) 4
redis 127.0.0.1:6379> lpop mykey
"d"
redis 127.0.0.1:6379> lpop mykey
"c"
#在执行lpop命令两次后,链表头部的两个元素已经被弹出,此时链表中元素的数量是2
redis 127.0.0.1:6379> llen mykey
(integer) 2

3). LREM/LSET/LINDEX/LTRIM:

#为后面的示例准备测试数据。
redis 127.0.0.1:6379> lpush mykey a b c d a c
(integer) 6
#从头部(left)向尾部(right)变量链表,删除2个值等于a的元素,返回值为实际删除的数量。
redis 127.0.0.1:6379> lrem mykey 2 a
(integer) 2
#看出删除后链表中的全部元素。
redis 127.0.0.1:6379> lrange mykey 0 -1
1) "c"
2) "d"
3) "c"
4) "b"
#获取索引值为1(头部的第二个元素)的元素值。
redis 127.0.0.1:6379> lindex mykey 1
"d"
#将索引值为1(头部的第二个元素)的元素值设置为新值e。
redis 127.0.0.1:6379> lset mykey 1 e
OK
#查看是否设置成功。
redis 127.0.0.1:6379> lindex mykey 1
"e"
#索引值6超过了链表中元素的数量,该命令返回nil。
redis 127.0.0.1:6379> lindex mykey 6
(nil)
#设置的索引值6超过了链表中元素的数量,设置失败,该命令返回错误信息。
redis 127.0.0.1:6379> lset mykey 6 hh
(error) ERR index out of range
#仅保留索引值0到2之间的3个元素,注意第0个和第2个元素均被保留。
redis 127.0.0.1:6379> ltrim mykey 0 2
OK
#查看trim后的结果。
redis 127.0.0.1:6379> lrange mykey 0 -1
1) "c"
2) "e"
3) "c"

4). LINSERT:

#删除该键便于后面的测试。
redis 127.0.0.1:6379> del mykey
(integer) 1
#为后面的示例准备测试数据。
redis 127.0.0.1:6379> lpush mykey a b c d e
(integer) 5
#在a的前面插入新元素a1。
redis 127.0.0.1:6379> linsert mykey before a a1
(integer) 6
#查看是否插入成功,从结果看已经插入。注意lindex的index值是0-based。
redis 127.0.0.1:6379> lindex mykey 0
"e"
#在e的后面插入新元素e2,从返回结果看已经插入成功。
redis 127.0.0.1:6379> linsert mykey after e e2
(integer) 7
#再次查看是否插入成功。
redis 127.0.0.1:6379> lindex mykey 1
"e2"
#在不存在的元素之前或之后插入新元素,该命令操作失败,并返回-1。
redis 127.0.0.1:6379> linsert mykey after k a
(integer) -1
#为不存在的Key插入新元素,该命令操作失败,返回0。
redis 127.0.0.1:6379> linsert mykey1 after a a2
(integer) 0

5). RPUSH/RPUSHX/RPOP/RPOPLPUSH:

#删除该键,以便于后面的测试。
redis 127.0.0.1:6379> del mykey
(integer) 1
#从链表的尾部插入参数中给出的values,插入顺序是从左到右依次插入。
redis 127.0.0.1:6379> rpush mykey a b c d
(integer) 4
#通过lrange的可以获悉rpush在插入多值时的插入顺序。
redis 127.0.0.1:6379> lrange mykey 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
#该键已经存在并且包含4个元素,rpushx命令将执行成功,并将元素e插入到链表的尾部。
redis 127.0.0.1:6379> rpushx mykey e
(integer) 5
#通过lindex命令可以看出之前的rpushx命令确实执行成功,因为索引值为4的元素已经是新元素了。
redis 127.0.0.1:6379> lindex mykey 4
"e"
#由于mykey2键并不存在,因此该命令不会插入数据,其返回值为0。
redis 127.0.0.1:6379> rpushx mykey2 e
(integer) 0
#在执行rpoplpush命令前,先看一下mykey中链表的元素有哪些,注意他们的位置关系。
redis 127.0.0.1:6379> lrange mykey 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
#将mykey的尾部元素e弹出,同时再插入到mykey2的头部(原子性的完成这两步操作)。
redis 127.0.0.1:6379> rpoplpush mykey mykey2
"e"
#通过lrange命令查看mykey在弹出尾部元素后的结果。
redis 127.0.0.1:6379> lrange mykey 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
#通过lrange命令查看mykey2在插入元素后的结果。
redis 127.0.0.1:6379> lrange mykey2 0 -1
1) "e"
#将source和destination设为同一键,将mykey中的尾部元素移到其头部。
redis 127.0.0.1:6379> rpoplpush mykey mykey
"d"
#查看移动结果。
redis 127.0.0.1:6379> lrange mykey 0 -1
1) "d"
2) "a"
3) "b"
4) "c"

三、hash所有命令

1、相关命令列表说明:


命令原型 时间复杂度 命令描述 返回值
HSET key field value 为指定的Key设定Field/Value对,如果Key不存在,该命令将创建新Key以参数中的Field/Value对,如果参数中的Field在该Key中已经存在,则用新值覆盖其原有值。 1表示新的Field被设置了新值,0表示Field已经存在,用新值覆盖原有值。
HGET key field 返回指定Key中指定Field的关联值。 返回参数中Field的关联值,如果参数中的Key或Field不存,返回nil。

HEXISTS key field 判断指定Key中的指定Field是否存在。 1表示存在,0表示参数中的Field或Key不存在。
HLEN key 获取该Key所包含的Field的数量。 返回Key包含的Field数量,如果Key不存在,返回0。

HDEL key field [field ...] 从指定Key的Hashes Value中删除参数中指定的多个字段,如果不存在的字段将被忽略。如果Key不存在,则将其视为空Hashes,并返回0. 实际删除的Field数量。
HSETNX key field value 只有当参数中的Key或Field不存在的情况下,为指定的Key设定Field/Value对,否则该命令不会进行任何操作。 1表示新的Field被设置了新值,0表示Key或Field已经存在,该命令没有进行任何操作。
HINCRBY key field increment 增加指定Key中指定Field关联的Value的值。如果Key或Field不存在,该命令将会创建一个新Key或新Field,并将其关联的Value初始化为0,之后再指定数字增加的操作。该命令支持的数字是64位有符号整型,即increment可以负数。 返回运算后的值。

HGETALL key 获取该键包含的所有Field/Value。其返回格式为一个Field、一个Value,并以此类推。 Field/Value的列表。
HKEYS key 返回指定Key的所有Fields名。 Field的列表。
HVALS key 返回指定Key的所有Values名。 Value的列表。
HMGET key field [field ...] 获取和参数中指定Fields关联的一组Values。如果请求的Field不存在,其值返回nil。如果Key不存在,该命令将其视为空Hash,因此返回一组nil。 返回和请求Fields关联的一组Values,其返回顺序等同于Fields的请求顺序。
HMSET key field value [field value ...] 逐对依次设置参数中给出的Field/Value对。如果其中某个Field已经存在,则用新值覆盖原有值。如果Key不存在,则创建新Key,同时设定参数中的Field/Value。

2、命令示例:


1). HSET/HGET/HDEL/HEXISTS/HLEN/HSETNX:

#在Shell命令行启动Redis客户端程序
/> redis-cli
#给键值为myhash的键设置字段为field1,值为stephen。
redis 127.0.0.1:6379> hset myhash field1 "stephen"
(integer) 1
#获取键值为myhash,字段为field1的值。
redis 127.0.0.1:6379> hget myhash field1
"stephen"
#myhash键中不存在field2字段,因此返回nil。
redis 127.0.0.1:6379> hget myhash field2
(nil)
#给myhash关联的Hashes值添加一个新的字段field2,其值为liu。
redis 127.0.0.1:6379> hset myhash field2 "liu"
(integer) 1
#获取myhash键的字段数量。
redis 127.0.0.1:6379> hlen myhash
(integer) 2
#判断myhash键中是否存在字段名为field1的字段,由于存在,返回值为1。
redis 127.0.0.1:6379> hexists myhash field1
(integer) 1
#删除myhash键中字段名为field1的字段,删除成功返回1。
redis 127.0.0.1:6379> hdel myhash field1
(integer) 1
#再次删除myhash键中字段名为field1的字段,由于上一条命令已经将其删除,因为没有删除,返回0。
redis 127.0.0.1:6379> hdel myhash field1
(integer) 0
#判断myhash键中是否存在field1字段,由于上一条命令已经将其删除,因为返回0。
redis 127.0.0.1:6379> hexists myhash field1
(integer) 0
#通过hsetnx命令给myhash添加新字段field1,其值为stephen,因为该字段已经被删除,所以该命令添加成功并返回1。
redis 127.0.0.1:6379> hsetnx myhash field1 stephen
(integer) 1
#由于myhash的field1字段已经通过上一条命令添加成功,因为本条命令不做任何操作后返回0。
redis 127.0.0.1:6379> hsetnx myhash field1 stephen
(integer) 0

2). HINCRBY:

#删除该键,便于后面示例的测试。
redis 127.0.0.1:6379> del myhash
(integer) 1
#准备测试数据,该myhash的field字段设定值1。
redis 127.0.0.1:6379> hset myhash field 5
(integer) 1
#给myhash的field字段的值加1,返回加后的结果。
redis 127.0.0.1:6379> hincrby myhash field 1
(integer) 6
#给myhash的field字段的值加-1,返回加后的结果。
redis 127.0.0.1:6379> hincrby myhash field -1
(integer) 5
#给myhash的field字段的值加-10,返回加后的结果。
redis 127.0.0.1:6379> hincrby myhash field -10
(integer) -5

3). HGETALL/HKEYS/HVALS/HMGET/HMSET:

#删除该键,便于后面示例测试。
redis 127.0.0.1:6379> del myhash
(integer) 1
#为该键myhash,一次性设置多个字段,分别是field1 = "hello", field2 = "world"。
redis 127.0.0.1:6379> hmset myhash field1 "hello" field2 "world"
OK
#获取myhash键的多个字段,其中field3并不存在,因为在返回结果中与该字段对应的值为nil。
redis 127.0.0.1:6379> hmget myhash field1 field2 field3
1) "hello"
2) "world"
3) (nil)
#返回myhash键的所有字段及其值,从结果中可以看出,他们是逐对列出的。
redis 127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hello"
3) "field2"
4) "world"
#仅获取myhash键中所有字段的名字。
redis 127.0.0.1:6379> hkeys myhash
1) "field1"
2) "field2"
#仅获取myhash键中所有字段的值。
redis 127.0.0.1:6379> hvals myhash
1) "hello"
2) "world"

四、set所有命令

1、相关命令列表说明:


命令原型 时间复杂度 命令描述 返回值
SADD key member [member ...] 如果在插入的过程用,参数中有的成员在Set中已经存在,该成员将被忽略,而其它成员仍将会被正常插入。如果执行该命令之前,该Key并不存在,该命令将会创建一个新的Set,此后再将参数中的成员陆续插入。如果该Key的Value不是Set类型,该命令将返回相关的错误信息。 本次操作实际插入的成员数量。
SCARD key 获取Set中成员的数量。 返回Set中成员的数量,如果该Key并不存在,返回0。
SISMEMBER key member 判断参数中指定成员是否已经存在于与Key相关联的Set集合中。 1表示已经存在,0表示不存在,或该Key本身并不存在。
SMEMBERS key 获取与该Key关联的Set中所有的成员。返回Set中所有的成员。
Skey 随机的移除并返回Set中的某一成员。 由于Set中元素的布局不受外部控制,因此无法像List那样确定哪个元素位于Set的头部或者尾部。 返回移除的成员,如果该Key并不存在,则返回nil。
SREM key member [member ...] 从与Key关联的Set中删除参数中指定的成员,不存在的参数成员将被忽略,如果该Key并不存在,将视为空Set处理。 从Set中实际移除的成员数量,如果没有则返回0。
SRANDMEMBER key 和SPOP一样,随机的返回Set中的一个成员,不同的是该命令并不会删除返回的成员。 返回随机位置的成员,如果Key不存在则返回nil。
SMOVE source destination member 原子性的将参数中的成员从source键移入到destination键所关联的Set中。因此在某一时刻,该成员或者出现在source中,或者出现在destination中。如果该成员在source中并不存在,该命令将不会再执行任何操作并返回0,否则,该成员将从source移入到destination。如果此时该成员已经在destination中存在,那么该命令仅是将该成员从source中移出。如果和Key关联的Value不是Set,将返回相关的错误信息。 1表示正常移动,0表示source中并不包含参数成员。
SDIFF key [key ...] 返回参数中第一个Key所关联的Set和其后所有Keys所关联的Sets中成员的差异。如果Key不存在,则视为空Set。 差异结果成员的集合。
SDIFFSTORE destination key [key ...] 该命令和SDIFF命令在功能上完全相同,两者之间唯一的差别是SDIFF返回差异的结果成员,而该命令将差异成员存储在destination关联的Set中。如果destination键已经存在,该操作将覆盖它的成员。 返回差异成员的数量。
SINTER key [key ...] 该命令将返回参数中所有Keys关联的Sets中成员的交集。因此如果参数中任何一个Key关联的Set为空,或某一Key不存在,那么该命令的结果将为空集。 交集结果成员的集合。
SINTERSTORE destination key [key ...] 该命令和SINTER命令在功能上完全相同,两者之间唯一的差别是SINTER返回交集的结果成员,而该命令将交集成员存储在destination关联的Set中。如果destination键已经存在,该操作将覆盖它的成员。 返回交集成员的数量。
SUNION key [key ...] 该命令将返回参数中所有Keys关联的Sets中成员的并集。 并集结果成员的集合。
SUNIONSTORE destination key [key ...] 该命令和SUNION命令在功能上完全相同,两者之间唯一的差别是SUNION返回并集的结果成员,而该命令将并集成员存储在destination关联的Set中。如果destination键已经存在,该操作将覆盖它的成员。 返回并集成员的数量。

2、命令示例:


1). SADD/SMEMBERS/SCARD/SISMEMBER:

#在Shell命令行下启动Redis的客户端程序。
/> redis-cli
#插入测试数据,由于该键myset之前并不存在,因此参数中的三个成员都被正常插入。
redis 127.0.0.1:6379> sadd myset a b c
(integer) 3
#由于参数中的a在myset中已经存在,因此本次操作仅仅插入了d和e两个新成员。
redis 127.0.0.1:6379> sadd myset a d e
(integer) 2
#判断a是否已经存在,返回值为1表示存在。
redis 127.0.0.1:6379> sismember myset a
(integer) 1
#判断f是否已经存在,返回值为0表示不存在。
redis 127.0.0.1:6379> sismember myset f
(integer) 0
#通过smembers命令查看插入的结果,从结果可以,输出的顺序和插入顺序无关。
redis 127.0.0.1:6379> smembers myset
1) "c"
2) "d"
3) "a"
4) "b"
5) "e"
#获取Set集合中元素的数量。
redis 127.0.0.1:6379> scard myset
(integer) 5

2). SPOP/SREM/SRANDMEMBER/SMOVE:

#删除该键,便于后面的测试。
redis 127.0.0.1:6379> del myset
(integer) 1
#为后面的示例准备测试数据。
redis 127.0.0.1:6379> sadd myset a b c d
(integer) 4
#查看Set中成员的位置。
redis 127.0.0.1:6379> smembers myset
1) "c"
2) "d"
3) "a"
4) "b"
#从结果可以看出,该命令确实是随机的返回了某一成员。
redis 127.0.0.1:6379> srandmember myset
"c"
#Set中尾部的成员b被移出并返回,事实上b并不是之前插入的第一个或最后一个成员。
redis 127.0.0.1:6379> spop myset
"b"
#查看移出后Set的成员信息。
redis 127.0.0.1:6379> smembers myset
1) "c"
2) "d"
3) "a"
#从Set中移出a、d和f三个成员,其中f并不存在,因此只有a和d两个成员被移出,返回为2。
redis 127.0.0.1:6379> srem myset a d f
(integer) 2
#查看移出后的输出结果。
redis 127.0.0.1:6379> smembers myset
1) "c"
#为后面的smove命令准备数据。
redis 127.0.0.1:6379> sadd myset a b
(integer) 2
redis 127.0.0.1:6379> sadd myset2 c d
(integer) 2
#将a从myset移到myset2,从结果可以看出移动成功。
redis 127.0.0.1:6379> smove myset myset2 a
(integer) 1
#再次将a从myset移到myset2,由于此时a已经不是myset的成员了,因此移动失败并返回0。
redis 127.0.0.1:6379> smove myset myset2 a
(integer) 0
#分别查看myset和myset2的成员,确认移动是否真的成功。
redis 127.0.0.1:6379> smembers myset
1) "b"
redis 127.0.0.1:6379> smembers myset2
1) "c"
2) "d"
3) "a"

3). SDIFF/SDIFFSTORE/SINTER/SINTERSTORE:

#为后面的命令准备测试数据。
redis 127.0.0.1:6379> sadd myset a b c d
(integer) 4
redis 127.0.0.1:6379> sadd myset2 c
(integer) 1
redis 127.0.0.1:6379> sadd myset3 a c e
(integer) 3
#myset和myset2相比,a、b和d三个成员是两者之间的差异成员。再用这个结果继续和myset3进行差异比较,b和d是myset3不存在的成员。
redis 127.0.0.1:6379> sdiff myset myset2 myset3
1) "d"
2) "b"
#将3个集合的差异成员存在在diffkey关联的Set中,并返回插入的成员数量。
redis 127.0.0.1:6379> sdiffstore diffkey myset myset2 myset3
(integer) 2
#查看一下sdiffstore的操作结果。
redis 127.0.0.1:6379> smembers diffkey
1) "d"
2) "b"
#从之前准备的数据就可以看出,这三个Set的成员交集只有c。
redis 127.0.0.1:6379> sinter myset myset2 myset3
1) "c"
#将3个集合中的交集成员存储到与interkey关联的Set中,并返回交集成员的数量。
redis 127.0.0.1:6379> sinterstore interkey myset myset2 myset3
(integer) 1
#查看一下sinterstore的操作结果。
redis 127.0.0.1:6379> smembers interkey
1) "c"
#获取3个集合中的成员的并集。
redis 127.0.0.1:6379> sunion myset myset2 myset3
1) "b"
2) "c"
3) "d"
4) "e"
5) "a"
#将3个集合中成员的并集存储到unionkey关联的set中,并返回并集成员的数量。
redis 127.0.0.1:6379> sunionstore unionkey myset myset2 myset3
(integer) 5
#查看一下suiionstore的操作结果。
redis 127.0.0.1:6379> smembers unionkey
1) "b"
2) "c"
3) "d"
4) "e"
5) "a"

五、soredset所有命令

1、相关命令列表说明:


命令原型 时间复杂度 命令描述 返回值
ZADD key score member [score] [member] 添加参数中指定的所有成员及其分数到指定key的Sorted-Set中,在该命令中我们可以指定多组score/member作为参数。如果在添加时参数中的某一成员已经存在,该命令将更新此成员的分数为新值,同时再将该成员基于新值重新排序。如果键不存在,该命令将为该键创建一个新的Sorted-Sets Value,并将score/member对插入其中。如果该键已经存在,但是与其关联的Value不是Sorted-Sets类型,相关的错误信息将被返回。 本次操作实际插入的成员数量。
ZCARD key 获取与该Key相关联的Sorted-Sets中包含的成员数量。 返回Sorted-Sets中的成员数量,如果该Key不存在,返回0。
ZCOUNT key min max 该命令用于获取分数(score)在min和max之间的成员数量。针对min和max参数需要额外说明的是,-inf和+inf分别表示Sorted-Sets中分数的最高值和最低值。缺省情况下,min和max表示的范围是闭区间范围,即min <= score <= max内的成员将被返回。然而我们可以通过在min和max的前面添加"("字符来表示开区间,如(min max表示min < score <= max,而(min (max表示min < score < max。 分数指定范围内成员的数量。
ZINCRBY key increment member 该命令将为指定Key中的指定成员增加指定的分数。如果成员不存在,该命令将添加该成员并假设其初始分数为0,此后再将其分数加上increment。如果Key不存,该命令将创建该Key及其关联的Sorted-Sets,并包含参数指定的成员,其分数为increment参数。如果与该Key关联的不是Sorted-Sets类型,相关的错误信息将被返回。 以字符串形式表示的新分数。
ZRANGE key start stop [WITHSCORES] 该命令返回顺序在参数start和stop指定范围内的成员,这里start和stop参数都是0-based,即0表示第一个成员,-1表示最后一个成员。如果start大于该Sorted-Set中的最大索引值,或start > stop,此时一个空集合将被返回。如果stop大于最大索引值,该命令将返回从start到集合的最后一个成员。如果命令中带有可选参数WITHSCORES选项,该命令在返回的结果中将包含每个成员的分数值,如value1,score1,value2,score2...。   返回索引在start和stop之间的成员列表。
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] 该命令将返回分数在min和max之间的所有成员,即满足表达式min <= score <= max的成员,其中返回的成员是按照其分数从低到高的顺序返回,如果成员具有相同的分数,则按成员的字典顺序返回。可选参数LIMIT用于限制返回成员的数量范围。可选参数offset表示从符合条件的第offset个成员开始返回,同时返回count个成员。可选参数WITHSCORES的含义参照ZRANGE中该选项的说明。最后需要说明的是参数中min和max的规则可参照命令ZCOUNT。 返回分数在指定范围内的成员列表。
ZRANK key member Sorted-Set中的成员都是按照分数从低到高的顺序存储,该命令将返回参数中指定成员的位置值,其中0表示第一个成员,它是Sorted-Set中分数最低的成员。 如果该成员存在,则返回它的位置索引值。否则返回nil。
ZREM key member [member ...] 该命令将移除参数中指定的成员,其中不存在的成员将被忽略。如果与该Key关联的Value不是Sorted-Set,相应的错误信息将被返回。 实际被删除的成员数量。
ZREVRANGE key start stop [WITHSCORES] 该命令的功能和ZRANGE基本相同,唯一的差别在于该命令是通过反向排序获取指定位置的成员,即从高到低的顺序。如果成员具有相同的分数,则按降序字典顺序排序。 返回指定的成员列表。
ZREVRANK key member 该命令的功能和ZRANK基本相同,唯一的差别在于该命令获取的索引是从高到低排序后的位置,同样0表示第一个元素,即分数最高的成员。 如果该成员存在,则返回它的位置索引值。否则返回nil。
ZSCORE key member 获取指定Key的指定成员的分数。 如果该成员存在,以字符串的形式返回其分数,否则返回nil。
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count] 该命令除了排序方式是基于从高到低的分数排序之外,其它功能和参数含义均与ZRANGEBYSCORE相同。 返回分数在指定范围内的成员列表。
ZREMRANGEBYRANK key start stop 删除索引位置位于start和stop之间的成员,start和stop都是0-based,即0表示分数最低的成员,-1表示最后一个成员,即分数最高的成员。 被删除的成员数量。
ZREMRANGEBYSCORE key min max 删除分数在min和max之间的所有成员,即满足表达式min <= score <= max的所有成员。对于min和max参数,可以采用开区间的方式表示,具体规则参照ZCOUNT。 被删除的成员数量。

2、命令示例:


1). ZADD/ZCARD/ZCOUNT/ZREM/ZINCRBY/ZSCORE/ZRANGE/ZRANK:

#在Shell的命令行下启动Redis客户端工具。
/> redis-cli
#添加一个分数为1的成员。
redis 127.0.0.1:6379> zadd myzset 1 "one"
(integer) 1
#添加两个分数分别是2和3的两个成员。
redis 127.0.0.1:6379> zadd myzset 2 "two" 3 "three"
(integer) 2
#0表示第一个成员,-1表示最后一个成员。WITHSCORES选项表示返回的结果中包含每个成员及其分数,否则只返回成员。
redis 127.0.0.1:6379> zrange myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
#获取成员one在Sorted-Set中的位置索引值。0表示第一个位置。
redis 127.0.0.1:6379> zrank myzset one
(integer) 0
#成员four并不存在,因此返回nil。
redis 127.0.0.1:6379> zrank myzset four
(nil)
#获取myzset键中成员的数量。
redis 127.0.0.1:6379> zcard myzset
(integer) 3
#返回与myzset关联的Sorted-Set中,分数满足表达式1 <= score <= 2的成员的数量。
redis 127.0.0.1:6379> zcount myzset 1 2
(integer) 2
#删除成员one和two,返回实际删除成员的数量。
redis 127.0.0.1:6379> zrem myzset one two
(integer) 2
#查看是否删除成功。
redis 127.0.0.1:6379> zcard myzset
(integer) 1
#获取成员three的分数。返回值是字符串形式。
redis 127.0.0.1:6379> zscore myzset three
"3"
#由于成员two已经被删除,所以该命令返回nil。
redis 127.0.0.1:6379> zscore myzset two
(nil)
#将成员one的分数增加2,并返回该成员更新后的分数。
redis 127.0.0.1:6379> zincrby myzset 2 one
"3"
#将成员one的分数增加-1,并返回该成员更新后的分数。
redis 127.0.0.1:6379> zincrby myzset -1 one
"2"
#查看在更新了成员的分数后是否正确。
redis 127.0.0.1:6379> zrange myzset 0 -1 WITHSCORES
1) "one"
2) "2"
3) "two"
4) "2"
5) "three"
6) "3"

2). ZRANGEBYSCORE/ZREMRANGEBYRANK/ZREMRANGEBYSCORE

redis 127.0.0.1:6379> del myzset
(integer) 1
redis 127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
#获取分数满足表达式1 <= score <= 2的成员。
redis 127.0.0.1:6379> zrangebyscore myzset 1 2
1) "one"
2) "two"
#获取分数满足表达式1 < score <= 2的成员。
redis 127.0.0.1:6379> zrangebyscore myzset (1 2
1) "two"
#-inf表示第一个成员,+inf表示最后一个成员,limit后面的参数用于限制返回成员的自己,
#2表示从位置索引(0-based)等于2的成员开始,去后面3个成员。
redis 127.0.0.1:6379> zrangebyscore myzset -inf +inf limit 2 3
1) "three"
2) "four"
#删除分数满足表达式1 <= score <= 2的成员,并返回实际删除的数量。
redis 127.0.0.1:6379> zremrangebyscore myzset 1 2
(integer) 2
#看出一下上面的删除是否成功。
redis 127.0.0.1:6379> zrange myzset 0 -1
1) "three"
2) "four"
#删除位置索引满足表达式0 <= rank <= 1的成员。
redis 127.0.0.1:6379> zremrangebyrank myzset 0 1
(integer) 2
#查看上一条命令是否删除成功。
redis 127.0.0.1:6379> zcard myzset
(integer) 0

3). ZREVRANGE/ZREVRANGEBYSCORE/ZREVRANK:

#为后面的示例准备测试数据。
redis 127.0.0.1:6379> del myzset
(integer) 0
redis 127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
#以位置索引从高到低的方式获取并返回此区间内的成员。
redis 127.0.0.1:6379> zrevrange myzset 0 -1 WITHSCORES
1) "four"
2) "4"
3) "three"
4) "3"
5) "two"
6) "2"
7) "one"
8) "1"
#由于是从高到低的排序,所以位置等于0的是four,1是three,并以此类推。
redis 127.0.0.1:6379> zrevrange myzset 1 3
1) "three"
2) "two"
3) "one"
#由于是从高到低的排序,所以one的位置是3。
redis 127.0.0.1:6379> zrevrank myzset one
(integer) 3
#由于是从高到低的排序,所以four的位置是0。
redis 127.0.0.1:6379> zrevrank myzset four
(integer) 0
#获取分数满足表达式3 >= score >= 0的成员,并以相反的顺序输出,即从高到底的顺序。
redis 127.0.0.1:6379> zrevrangebyscore myzset 3 0
1) "three"
2) "two"
3) "one"
#该命令支持limit选项,其含义等同于zrangebyscore中的该选项,只是在计算位置时按照相反的顺序计算和获取。
redis 127.0.0.1:6379> zrevrangebyscore myzset 4 0 limit 1 2
1) "three"
2) "two"

六、key所有命令

1、相关命令列表说明:


命令原型 时间复杂度 命令描述 返回值
KEYS pattern 获取所有匹配pattern参数的Keys。需要说明的是,在我们的正常操作中应该尽量避免对该命令的调用,因为对于大型数据库而言,该命令是非常耗时的,对Redis服务器的性能打击也是比较大的。pattern支持glob-style的通配符格式,如*表示任意一个或多个字符,?表示任意字符,[abc]表示方括号中任意一个字母。 匹配模式的键列表。
DEL key [key ...] 从数据库删除中参数中指定的keys,如果指定键不存在,则直接忽略。还需要另行指出的是,如果指定的Key关联的数据类型不是String类型,而是List、Set、Hashes和Sorted Set等容器类型,该命令删除每个键的时间复杂度为O(M),其中M表示容器中元素的数量。而对于String类型的Key,其时间复杂度为O(1)。 实际被删除的Key数量。
EXISTS key 判断指定键是否存在。 1表示存在,0表示不存在。
MOVE key db 将当前数据库中指定的键Key移动到参数中指定的数据库中。如果该Key在目标数据库中已经存在,或者在当前数据库中并不存在,该命令将不做任何操作并返回0。 移动成功返回1,否则0。
RENAME key newkey 为指定指定的键重新命名,如果参数中的两个Keys的名字相同,或者是源Key不存在,该命令都会返回相关的错误信息。如果newKey已经存在,则直接覆盖。
RENAMENX key newkey 如果新值不存在,则将参数中的原值修改为新值。其它条件和RENAME一致。 1表示修改成功,否则0。
PERSIST key 如果Key存在过期时间,该命令会将其过期时间消除,使该Key不再有超时,而是可以持久化存储。 1表示Key的过期时间被移出,0表示该Key不存在或没有过期时间。
EXPIRE key seconds 该命令为参数中指定的Key设定超时的秒数,在超过该时间后,Key被自动的删除。如果该Key在超时之前被修改,与该键关联的超时将被移除。 1表示超时被设置,0则表示Key不存在,或不能被设置。
EXPIREAT key timestamp 该命令的逻辑功能和EXPIRE完全相同,唯一的差别是该命令指定的超时时间是绝对时间,而不是相对时间。该时间参数是Unix timestamp格式的,即从1970年1月1日开始所流经的秒数。 1表示超时被设置,0则表示Key不存在,或不能被设置。
TTL key 获取该键所剩的超时描述。 返回所剩描述,如果该键不存在或没有超时设置,则返回-1。
RANDOMKEY 从当前打开的数据库中随机的返回一个Key。 返回的随机键,如果该数据库是空的则返回nil。
TYPE key 获取与参数中指定键关联值的类型,该命令将以字符串的格式返回。 返回的字符串为string、list、set、hash和zset,如果key不存在返回none。


2、命令示例:


1). KEYS/RENAME/DEL/EXISTS/MOVE/RENAMENX:

#在Shell命令行下启动Redis客户端工具。
/> redis-cli
#清空当前选择的数据库,以便于对后面示例的理解。
redis 127.0.0.1:6379> flushdb
OK
#添加String类型的模拟数据。
redis 127.0.0.1:6379> set mykey 2
OK
redis 127.0.0.1:6379> set mykey2 "hello"
OK
#添加Set类型的模拟数据。
redis 127.0.0.1:6379> sadd mysetkey 1 2 3
(integer) 3
#添加Hash类型的模拟数据。
redis 127.0.0.1:6379> hset mmtest username "stephen"
(integer) 1
#根据参数中的模式,获取当前数据库中符合该模式的所有key,从输出可以看出,该命令在执行时并不区分与Key关联的Value类型。
redis 127.0.0.1:6379> keys my*
1) "mysetkey"
2) "mykey"
3) "mykey2"
#删除了两个Keys。
redis 127.0.0.1:6379> del mykey mykey2
(integer) 2
#查看一下刚刚删除的Key是否还存在,从返回结果看,mykey确实已经删除了。
redis 127.0.0.1:6379> exists mykey
(integer) 0
#查看一下没有删除的Key,以和上面的命令结果进行比较。
redis 127.0.0.1:6379> exists mysetkey
(integer) 1
#将当前数据库中的mysetkey键移入到ID为1的数据库中,从结果可以看出已经移动成功。
redis 127.0.0.1:6379> move mysetkey 1
(integer) 1
#打开ID为1的数据库。
redis 127.0.0.1:6379> select 1
OK
#查看一下刚刚移动过来的Key是否存在,从返回结果看已经存在了。
redis 127.0.0.1:6379[1]> exists mysetkey
(integer) 1
#在重新打开ID为0的缺省数据库。
redis 127.0.0.1:6379[1]> select 0
OK
#查看一下刚刚移走的Key是否已经不存在,从返回结果看已经移走。
redis 127.0.0.1:6379> exists mysetkey
(integer) 0
#准备新的测试数据。
redis 127.0.0.1:6379> set mykey "hello"
OK
#将mykey改名为mykey1
redis 127.0.0.1:6379> rename mykey mykey1
OK
#由于mykey已经被重新命名,再次获取将返回nil。
redis 127.0.0.1:6379> get mykey
(nil)
#通过新的键名获取。
redis 127.0.0.1:6379> get mykey1
"hello"
#由于mykey已经不存在了,所以返回错误信息。
redis 127.0.0.1:6379> rename mykey mykey1
(error) ERR no such key
#为renamenx准备测试key
redis 127.0.0.1:6379> set oldkey "hello"
OK
redis 127.0.0.1:6379> set newkey "world"
OK
#由于newkey已经存在,因此该命令未能成功执行。
redis 127.0.0.1:6379> renamenx oldkey newkey
(integer) 0
#查看newkey的值,发现它也没有被renamenx覆盖。
redis 127.0.0.1:6379> get newkey
"world"

2). PERSIST/EXPIRE/EXPIREAT/TTL:

#为后面的示例准备的测试数据。
redis 127.0.0.1:6379> set mykey "hello"
OK
#将该键的超时设置为100秒。
redis 127.0.0.1:6379> expire mykey 100
(integer) 1
#通过ttl命令查看一下还剩下多少秒。
redis 127.0.0.1:6379> ttl mykey
(integer) 97
#立刻执行persist命令,该存在超时的键变成持久化的键,即将该Key的超时去掉。
redis 127.0.0.1:6379> persist mykey
(integer) 1
#ttl的返回值告诉我们,该键已经没有超时了。
redis 127.0.0.1:6379> ttl mykey
(integer) -1
#为后面的expire命令准备数据。
redis 127.0.0.1:6379> del mykey
(integer) 1
redis 127.0.0.1:6379> set mykey "hello"
OK
#设置该键的超时被100秒。
redis 127.0.0.1:6379> expire mykey 100
(integer) 1
#用ttl命令看一下当前还剩下多少秒,从结果中可以看出还剩下96秒。
redis 127.0.0.1:6379> ttl mykey
(integer) 96
#重新更新该键的超时时间为20秒,从返回值可以看出该命令执行成功。
redis 127.0.0.1:6379> expire mykey 20
(integer) 1
#再用ttl确认一下,从结果中可以看出果然被更新了。
redis 127.0.0.1:6379> ttl mykey
(integer) 17
#立刻更新该键的值,以使其超时无效。
redis 127.0.0.1:6379> set mykey "world"
OK
#从ttl的结果可以看出,在上一条修改该键的命令执行后,该键的超时也无效了。
redis 127.0.0.1:6379> ttl mykey
(integer) -1

3). TYPE/RANDOMKEY/SORT:

#由于mm键在数据库中不存在,因此该命令返回none。
redis 127.0.0.1:6379> type mm
none
#mykey的值是字符串类型,因此返回string。
redis 127.0.0.1:6379> type mykey
string
#准备一个值是set类型的键。
redis 127.0.0.1:6379> sadd mysetkey 1 2
(integer) 2
#mysetkey的键是set,因此返回字符串set。
redis 127.0.0.1:6379> type mysetkey
set
#返回数据库中的任意键。
redis 127.0.0.1:6379> randomkey
"oldkey"
#清空当前打开的数据库。
redis 127.0.0.1:6379> flushdb
OK
#由于没有数据了,因此返回nil。
redis 127.0.0.1:6379> randomkey
(nil)










  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值