Redis:详解5大数据类型及其常用命令

目录

  • Redis键(key)
  • 字符串(String)
    • 简介
    • 常用命令
    • 数据结构
    • 简介
    • 常用命令
  • 列表(List)
    • 简介
    • 常用命令
    • 数据结构
  • 集合(Set)
    • 简介
    • 常用命令
    • 数据结构
  • 哈希(Hash)
    • 简介
    • 常用命令
    • 数据结构
  • 有序集合zset
    • 简介
    • 常用命令
    • 数据结构

这里说的数据类型是value的数据类型,key的类型都是字符串。

5种数据类型:

  • redis字符串(String)
  • redis列表(List)
  • redis集合(Set)
  • redis哈希表(Hash)
  • redis有序集合(Zset)

哪里去获取redis常用数据类型操作命令:http://redis.cn/commands.html

Redis键(key)

常用命令:

  • keys *:查看当前库所有的key
  • exists key:判断某个key是否存在
  • type key:查看你的key是什么类型
  • del key:删除指定的key数据
  • unlink key:根据value删除非阻塞删除,仅仅将keys从keyspace元数据中删除,真正的删除会在
  • 后续异步中操作。
  • expire key 10:为指定的key设置有效期10秒
  • ttl key:查看指定的key还有多少秒过期,-1:表示永不过期,-2:表示已过期
  • select dbindex:切换数据库【0-15】,默认为0
  • dbsize:查看当前数据库key的数量
  • flushdb:清空当前库
  • flushall:通杀全部库

字符串(String)

简介

String是Redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。

String类型是二进制安全的。意味着Redis的string可以包含任何数据。比如jpg图片或者序列化的对象。

String类型是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M。

常用命令

  1. set

添加键值对。

127.0.0.1:6379> set key value [EX seconds|PX milliseconds|EXAT timestamp|PXAT milliseconds-timestamp|KEEPTTL] [NX|XX] [GET]
  • NX:当数据库中key不存在时,可以将key-value添加到数据库
  • XX:当数据库中key存在时,可以将key-value添加数据库,与NX参数互斥
  • EX:key的超时秒数
  • PX:key的超时毫秒数,与EX互斥
  • value中若包含空格、特殊字符,需用双引号包裹
  1. get

获取值。

get <key>

示例

127.0.0.1:6379> set name ready 
OK
127.0.0.1:6379> get name 
"ready"
  1. apend

追加值。将给定的value追加到原值的末尾。

append <key> <value>

示例

127.0.0.1:6379> set k1 hello 
OK
127.0.0.1:6379> append k1 " world" 
(integer) 11 
127.0.0.1:6379> get k1 
"hello world"
  1. strlen

获取字符串长度

strlen <key>

示例

127.0.0.1:6379> set name ready 
OK
127.0.0.1:6379> strlen name 
(integer) 5
  1. setnx

key不存在时,设置key的值

setnx <key> <value>

示例

127.0.0.1:6379> flushdb #清空db,方便测试 
OK
127.0.0.1:6379> setnx site "itsoku.com" #site不存在,返回1,表示设置成功 
(integer) 1 
127.0.0.1:6379> setnx site "itsoku.com" #再次通过setnx设置site,由于已经存在了,所以设 置失败,返回0 
(integer) 0
  1. incr

原子递增1。将key中存储的值增1,只能对数字值操作,如果key不存在,则会新建一个,值为1

incr <key>

示例

127.0.0.1:6379> flushdb #清空db,方便测试 
OK
127.0.0.1:6379> set age 30 #age值为30 
OK
127.0.0.1:6379> incr age #age增加1,返回31 
(integer) 31 
127.0.0.1:6379> get age #获取age的值
"31" 
127.0.0.1:6379> incr salary #salary不存在,自动创建一个,值为1 
(integer) 1 
127.0.0.1:6379> get salary #获取salary的值 
"1"
  1. decr

原子递减1。将key中存储的值减1,只能对数字值操作,如果为空,新增值为-1。

decr <key>

示例

127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> set age 30 #age值为30 
OK
127.0.0.1:6379> decr age #age递减1,返回29 
(integer) 29 
127.0.0.1:6379> get age #获取age的值 
"29" 
127.0.0.1:6379> decr salary #salary不存在,自动创建一个,值为-1 
(integer) -1 
127.0.0.1:6379> get salary #获取salary 
"-1"
  1. incrby/decrby

递增或者递减指定的数字。将key中存储的数字值递增指定的步长,若key不存在,则相当于在原值为0的值上递增指定的步长。

incrby/decrby <key> <步长>

示例

127.0.0.1:6379> set salary 10000 #设置salary为10000 
OK
127.0.0.1:6379> incrby salary 5000 #salary添加5000,返回15000 
(integer) 15000 
127.0.0.1:6379> get salary #获取salary 
"15000" 
127.0.0.1:6379> decrby salary 800 #salary减去800,返回14200 
(integer) 14200 
127.0.0.1:6379> get salary #获取salary 
"14200"
  1. mset

同时设置多个key-value。

mset <key1> <value1> <key2> <value2> ...

示例

127.0.0.1:6379> mset name ready age 30 
OK
127.0.0.1:6379> get name 
"ready" 
127.0.0.1:6379> get age 
"30"
  1. mget

获取多个key对应的值

mget <key1> <key2> ...

示例

127.0.0.1:6379> mset name ready age 30 #同时设置name和age 
OK
127.0.0.1:6379> mget name age #同时读取name和age的值
1) "ready"
2) "30"
  1. msetnx

当多个key都不存在时,则设置成功。原子性的,要么都成功,或者都失败。

msetnx <key1> <value1> <key2> <value2> ...

示例

127.0.0.1:6379> flushdb #清空db,方便测试 
OK
127.0.0.1:6379> set k1 v1 #设置k1
OK
127.0.0.1:6379> msetnx k1 v1 k2 v2 #当k1和k2都不存在的时候,同时设置k1和k2,由于k1已存 在,所以这个操作失败
(integer) 0 
127.0.0.1:6379> mget k1 k2 #获取k1、k2,k2不存在 
1) "v1" 
2) (nil) 
127.0.0.1:6379> msetnx k2 v2 k3 v3 #当k2、h3都不存在的时候,同时设置k2和k3,设置成功 
(integer) 1 
127.0.0.1:6379> mget k1 k2 k3 #后去k1、k2、k3的值 
1) "v1"
2) "v2" 
3) "v3"
  1. getrange

获取值的范围,类似java中的substring。

getrange key start end
# 获取[start,end]返回为的字符串

示例

127.0.0.1:6379> set k1 helloworld 
OK
127.0.0.1:6379> getrange k1 0 4 
"hello"
  1. setrange

覆盖指定位置的值。

setrange <key> <起始位置> <value>

示例

127.0.0.1:6379> set k1 helloworld 
OK
127.0.0.1:6379> get k1 
"helloworld" 
127.0.0.1:6379> setrange k1 1 java 
(integer) 10
127.0.0.1:6379> get k1 
"hjavaworld"
  1. setex

设置键值&过期时间(秒)。

setex <key> <过期时间(秒)> <value>

示例

127.0.0.1:6379> setex k1 100 v1 #设置k1的值为v1,有效期100秒 
OK
127.0.0.1:6379> get k1 #获取k1的值 
"v1" 
127.0.0.1:6379> ttl k1 #获取k1还有多少秒失效
(integer) 96
  1. getset

以新换旧,设置新值同时返回旧值。

getset <key> <value>

示例

127.0.0.1:6379> set name ready #设置name为ready 
OK
127.0.0.1:6379> getset name tom #设置name为tom,返回name的旧值 
"ready" 
127.0.0.1:6379> getset age 30 #设置age为30,age未设置过,返回age的旧值为null 
(nil)

数据结构

String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS)。是可以修改的字符串,内部结构上类似于Java的ArrayList,采用分配冗余空间的方式来减少内存的频繁分配。

在这里插入图片描述

如图所示,内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次会多扩容1M的空间。要注意的是字符串最大长度为512M。

简介

单键多值。

redis列表是简单的字符串列表,按照插入顺序排序。

你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

它的底层实际上是使用双向链表实现的,对两端的操作性能很高,通过索引下标操作中间节点性能会较差。

常用命令

  1. lpush/rpush

从左边或者右边插入一个或多个值。

lpush/rpush <key1> <value1> <key2> <value2> ...

示例

127.0.0.1:6379> flushdb #清空db,方便测试 
OK
127.0.0.1:6379> rpush name java spring "springboot" "spring cloud" #列表name的左边 插入4个元素 
(integer) 4 
127.0.0.1:6379> lrange name 1 2 #从左边取出索引位于[1,2]范围内的元素 
1) "spring"
2) "springboot"
  1. lrange

从列表左边获取指定范围内的值。

lrange <key> <star> <stop>

返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。

下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1

表示列表的第二个元素,以此类推。

你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此

类推。

返回值:

一个列表,包含指定区间内的元素。

示例

127.0.0.1:6379> flushdb OK127.0.0.1:6379> rpush course java c c++ php js nodejs #course集合的右边插入6个元素
(integer) 6 
127.0.0.1:6379> lrange course 0 -1 #取出course集合中所有元素 
1) "java" 
2) "c" 
3) "c++" 
4) "php" 
5) "js" 
6) "nodejs" 
127.0.0.1:6379> lrange course 1 3 #获取course集合索引[1,3]范围内的元素
1) "c" 
2) "c++" 
3) "php
  1. lpop/rpop

从左边或者右边弹出多个元素

lpop/rpop <key> <count>

count:可以省略,默认值为1

lpop/rpop 操作之后,弹出来的值会从列表中删除

值在键在,值光键亡。

示例

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> rpush course java c++ php js node js #集合course右边加入6个元素 
(integer) 6 
127.0.0.1:6379> lpop course #从左边弹出1个元素 
"java" 
127.0.0.1:6379> rpop course 2 
#从右边弹出2个元素 
1) "js" 
2) "node"
  1. rpoplpush

从一个列表右边弹出一个元素放到另外一个列表中。

rpoplpush source destination
# 从source的右边弹出一个元素放到destination列表的左边

示例

127.0.0.1:6379> flushdb 
OK
127.0.0.1:6379> rpush k1 1 2 3 #列表k1的右边添加3个元素[1,2,3] 
(integer) 3 
127.0.0.1:6379> lrange k1 0 -1 #从左到右输出k1列表中的元素 
1) "1"
2) "2" 
3) "3" 
127.0.0.1:6379> rpush k2 4 5 6 #列表k2的右边添加3个元素[4,5,6] 
(integer) 3 
127.0.0.1:6379> lrange k2 0 -1 #从左到右输出k2列表中的元素
1) "4" 
2) "5" 
3) "6" 
127.0.0.1:6379> rpoplpush k1 k2 #从k1的右边弹出一个元素放到k2的左边
"3" 
127.0.0.1:6379> lrange k1 0 -1 #k1中剩下2个元素了 
1) "1" 
2) "2" 
127.0.0.1:6379> lrange k2 0 -1 #k2中变成4个元素了 
1) "3"
2) "4" 
3) "5" 
4) "6"
  1. lindex

获取指定索引位置的元素(从左到右)。

lindex key index

返回列表 key 中,下标为 index 的元素。

下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1

表示列表的第二个元素,以此类推。

你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此

类推。

如果 key 不是列表类型,返回一个错误。

返回值:

列表中下标为 index 的元素。

如果 index 参数的值不在列表的区间范围内(out of range),返回 nil

示例

127.0.0.1:6379> flushdb 
OK
127.0.0.1:6379> rpush course java c c++ php #列表course中放入4个元素 
(integer) 4 
127.0.0.1:6379> lindex course 2 #返回索引位置2的元素 
"c++" 
127.0.0.1:6379> lindex course 200 #返回索引位置200的元素,没有 
(nil) 
127.0.0.1:6379> lindex course -1 #返回最后一个元素 
"php"
  1. llen

获得列表长度

llen key

返回列表 key 的长度。

如果 key 不存在,则 key 被解释为一个空列表,返回 0 .

如果 key 不是列表类型,返回一个错误。

示例

127.0.0.1:6379> rpush name ready tom jack 
(integer) 3 
127.0.0.1:6379> llen name 
(integer) 3
  1. linsert

在某个值的前或者后面插入一个值

linsert <key> before|after <value> <newvalue>

将值 newvalue 插入到列表 key 当中,位于值 value 之前或之后。

当 value 不存在于列表 key 时,不执行任何操作。

当 key 不存在时, key 被视为空列表,不执行任何操作。

如果 key 不是列表类型,返回一个错误。

返回值:

如果命令执行成功,返回插入操作完成之后,列表的长度。

如果没有找到 value ,返回 -1 。

如果 key 不存在或为空列表,返回 0 。

示例

127.0.0.1:6379> flushdb 
OK
127.0.0.1:6379> rpush name ready tom jack #列表name中添加3个元素
(integer) 3 127.0.0.1:6379> lrange name 0 -1 #name列表所有元素 
1) "ready" 
2) "tom" 
3) "jack" 
127.0.0.1:6379> linsert name before tom lily #tom前面添加lily
(integer) 4 
127.0.0.1:6379> lrange name 0 -1 #name列表所有元素
1) "ready" 
2) "lily" 
3) "tom"
4) "jack" 
127.0.0.1:6379> linsert name before xxx lucy # 在元素xxx前面插入lucy,由于xxx元素不存 在,插入失败,返回-1 
(integer) -1 
127.0.0.1:6379> lrange name 0 -1
1) "ready" 
2) "lily"
3) "tom"
4) "jack"
  1. lrem

删除指定数量的某个元素

LREM key count value

根据参数 count 的值,移除列表中与参数 value 相等的元素。

count 的值可以是以下几种:

  • count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
  • count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
  • count = 0 : 移除表中所有与 value 相等的值。

返回值:

被移除元素的数量。

因为不存在的 key 被视作空表(empty list),所以当 key 不存在时,总是返回 0 。

示例

127.0.0.1:6379> rpush k1 v1 v2 v3 v2 v2 v1 #k1列表中插入6个元素
(integer) 6 
127.0.0.1:6379> lrange k1 0 -1 #输出k1集合中所有元素 
1) "v1" 2) "v2" 3) "v3" 4) "v2" 5) "v2" 6) "v1" 
127.0.0.1:6379> lrem k1 2 v2 #k1集合中从左边删除2个v2 
(integer) 2 
127.0.0.1:6379> lrange k1 0 -1 #输出列表,列表中还有1个v2,前面2个v2干掉了 
1) "v1" 2) "v3" 3) "v2" 4) "v1"
  1. lset

替换指定位置的值

lset <key> <index> <value>

将列表 key 下标为 index 的元素的值设置为 value 。 当 index 参数超出范围,或对一个空列表( key 不存在)进行lset时,返回一个错误。

**返回值:**操作成功返回 ok ,否则返回错误信息。

示例

127.0.0.1:6379> rpush name tom jack ready #name集合中放入3个元素
(integer) 3
127.0.0.1:6379> lrange name 0 -1 #输出name集合元素
1) "tom"
2) "jack"
3) "ready"
127.0.0.1:6379> lset name 1 lily #将name集合中第2个元素替换为liy
OK
127.0.0.1:6379> lrange name 0 -1 #输出name集合元素
1) "tom"
2) "lily"
3) "ready"
127.0.0.1:6379> lset name 10 lily #索引超出范围,报错
(error) ERR index out of range 
127.0.0.1:6379> lset course 1 java #course集合不存在,报错 
(error) ERR no such key

列表(List)

简介

单键多值。

redis列表是简单的字符串列表,按照插入顺序排序。

你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

它的底层实际上是使用双向链表实现的,对两端的操作性能很高,通过索引下标操作中间节点性能会较差。
在这里插入图片描述

常用命令

  1. lpush/rpush

从左边或者右边插入一个或多个值。

lpush/rpush <key1> <value1> <key2> <value2> ...

示例

127.0.0.1:6379> flushdb #清空db,方便测试 
OK
127.0.0.1:6379> rpush name java spring "springboot" "spring cloud" #列表name的左边 插入4个元素 
(integer) 4 
127.0.0.1:6379> lrange name 1 2 #从左边取出索引位于[1,2]范围内的元素 
1) "spring"
2) "springboot"
  1. lrange

从列表左边获取指定范围内的值。

lrange <key> <star> <stop>

返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。

下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1

表示列表的第二个元素,以此类推。

你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此

类推。

返回值:

一个列表,包含指定区间内的元素。

示例

127.0.0.1:6379> flushdb OK127.0.0.1:6379> rpush course java c c++ php js nodejs #course集合的右边插入6个元素
(integer) 6 
127.0.0.1:6379> lrange course 0 -1 #取出course集合中所有元素 
1) "java" 
2) "c" 
3) "c++" 
4) "php" 
5) "js" 
6) "nodejs" 
127.0.0.1:6379> lrange course 1 3 #获取course集合索引[1,3]范围内的元素
1) "c" 
2) "c++" 
3) "php
  1. lpop/rpop

从左边或者右边弹出多个元素

lpop/rpop <key> <count>

count:可以省略,默认值为1

lpop/rpop 操作之后,弹出来的值会从列表中删除

值在键在,值光键亡。

示例

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> rpush course java c++ php js node js #集合course右边加入6个元素 
(integer) 6 
127.0.0.1:6379> lpop course #从左边弹出1个元素 
"java" 
127.0.0.1:6379> rpop course 2 
#从右边弹出2个元素 
1) "js" 
2) "node"
  1. rpoplpush

从一个列表右边弹出一个元素放到另外一个列表中。

rpoplpush source destination
# 从source的右边弹出一个元素放到destination列表的左边

示例

127.0.0.1:6379> flushdb 
OK
127.0.0.1:6379> rpush k1 1 2 3 #列表k1的右边添加3个元素[1,2,3] 
(integer) 3 
127.0.0.1:6379> lrange k1 0 -1 #从左到右输出k1列表中的元素 
1) "1"
2) "2" 
3) "3" 
127.0.0.1:6379> rpush k2 4 5 6 #列表k2的右边添加3个元素[4,5,6] 
(integer) 3 
127.0.0.1:6379> lrange k2 0 -1 #从左到右输出k2列表中的元素
1) "4" 
2) "5" 
3) "6" 
127.0.0.1:6379> rpoplpush k1 k2 #从k1的右边弹出一个元素放到k2的左边
"3" 
127.0.0.1:6379> lrange k1 0 -1 #k1中剩下2个元素了 
1) "1" 
2) "2" 
127.0.0.1:6379> lrange k2 0 -1 #k2中变成4个元素了 
1) "3"
2) "4" 
3) "5" 
4) "6"
  1. lindex

获取指定索引位置的元素(从左到右)。

lindex key index

返回列表 key 中,下标为 index 的元素。

下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1

表示列表的第二个元素,以此类推。

你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此

类推。

如果 key 不是列表类型,返回一个错误。

返回值:

列表中下标为 index 的元素。

如果 index 参数的值不在列表的区间范围内(out of range),返回 nil

示例

127.0.0.1:6379> flushdb 
OK
127.0.0.1:6379> rpush course java c c++ php #列表course中放入4个元素 
(integer) 4 
127.0.0.1:6379> lindex course 2 #返回索引位置2的元素 
"c++" 
127.0.0.1:6379> lindex course 200 #返回索引位置200的元素,没有 
(nil) 
127.0.0.1:6379> lindex course -1 #返回最后一个元素 
"php"
  1. llen

获得列表长度

llen key

返回列表 key 的长度。

如果 key 不存在,则 key 被解释为一个空列表,返回 0 .

如果 key 不是列表类型,返回一个错误。

示例

127.0.0.1:6379> rpush name ready tom jack 
(integer) 3 
127.0.0.1:6379> llen name 
(integer) 3
  1. linsert

在某个值的前或者后面插入一个值

linsert <key> before|after <value> <newvalue>

将值 newvalue 插入到列表 key 当中,位于值 value 之前或之后。

当 value 不存在于列表 key 时,不执行任何操作。

当 key 不存在时, key 被视为空列表,不执行任何操作。

如果 key 不是列表类型,返回一个错误。

返回值:

如果命令执行成功,返回插入操作完成之后,列表的长度。

如果没有找到 value ,返回 -1 。

如果 key 不存在或为空列表,返回 0 。

示例

127.0.0.1:6379> flushdb 
OK
127.0.0.1:6379> rpush name ready tom jack #列表name中添加3个元素
(integer) 3 127.0.0.1:6379> lrange name 0 -1 #name列表所有元素 
1) "ready" 
2) "tom" 
3) "jack" 
127.0.0.1:6379> linsert name before tom lily #tom前面添加lily
(integer) 4 
127.0.0.1:6379> lrange name 0 -1 #name列表所有元素
1) "ready" 
2) "lily" 
3) "tom"
4) "jack" 
127.0.0.1:6379> linsert name before xxx lucy # 在元素xxx前面插入lucy,由于xxx元素不存 在,插入失败,返回-1 
(integer) -1 
127.0.0.1:6379> lrange name 0 -1
1) "ready" 
2) "lily"
3) "tom"
4) "jack"
  1. lrem

删除指定数量的某个元素

LREM key count value

根据参数 count 的值,移除列表中与参数 value 相等的元素。

count 的值可以是以下几种:

  • count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
  • count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
  • count = 0 : 移除表中所有与 value 相等的值。

返回值:

被移除元素的数量。

因为不存在的 key 被视作空表(empty list),所以当 key 不存在时,总是返回 0 。

示例

127.0.0.1:6379> rpush k1 v1 v2 v3 v2 v2 v1 #k1列表中插入6个元素
(integer) 6 
127.0.0.1:6379> lrange k1 0 -1 #输出k1集合中所有元素 
1) "v1" 2) "v2" 3) "v3" 4) "v2" 5) "v2" 6) "v1" 
127.0.0.1:6379> lrem k1 2 v2 #k1集合中从左边删除2个v2 
(integer) 2 
127.0.0.1:6379> lrange k1 0 -1 #输出列表,列表中还有1个v2,前面2个v2干掉了 
1) "v1" 2) "v3" 3) "v2" 4) "v1"
  1. lset

替换指定位置的值

lset <key> <index> <value>

将列表 key 下标为 index 的元素的值设置为 value 。 当 index 参数超出范围,或对一个空列表( key 不存在)进行lset时,返回一个错误。

**返回值:**操作成功返回 ok ,否则返回错误信息。

示例

127.0.0.1:6379> rpush name tom jack ready #name集合中放入3个元素
(integer) 3
127.0.0.1:6379> lrange name 0 -1 #输出name集合元素
1) "tom"
2) "jack"
3) "ready"
127.0.0.1:6379> lset name 1 lily #将name集合中第2个元素替换为liy
OK
127.0.0.1:6379> lrange name 0 -1 #输出name集合元素
1) "tom"
2) "lily"
3) "ready"
127.0.0.1:6379> lset name 10 lily #索引超出范围,报错
(error) ERR index out of range 
127.0.0.1:6379> lset course 1 java #course集合不存在,报错 
(error) ERR no such key

数据结构

List的数据结构为快速链表quickList。

首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也就是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当比较多的时候才会改成quickList。

因为普通的链表需要的附加指针空间太大,会比较浪费空间,比如这个列表里存储的只是int类型的书,结构上还需要2个额外的指针prev和next。
在这里插入图片描述

redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用,这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

集合(Set)

简介

redis set对外提供的功与list类似,是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择。

redis的set是string类型的无序集合,他的底层实际是一个value为null的hash表,收益添加,删除,查找复杂度都是O(1)。

一个算法,如果时间复杂度是O(1),那么随着数据的增加,查找数据的时间不变,也就是不管数据多少,查找时间都是一样的。

常用命令

  1. sadd

添加一个或多个元素

sadd <key> <value1> <value2> ...

示例

127.0.0.1:6379> sadd k1 v1 v2 v1 v3 v2 #k1中放入5个元素,会自动去重,成功插入3个 
(integer) 3
  1. smembers

取出所有元素

smembers <key>

示例

127.0.0.1:6379> sadd k1 v1 v2 v1 v3 v2 
(integer) 3 
127.0.0.1:6379> smembers k1 
1) "v2"
2) "v1" 
3) "v3"
  1. sismember

判断集合中是否有某个值

sismember <key> <value>

判断集合key中是否包含元素value,1:有,0:没有

示例

127.0.0.1:6379> sadd k1 v1 v2 v1 v3 v2 #k1集合中成功放入3个元素[v1,v2,v3]
(integer) 3
127.0.0.1:6379> sismember k1 v1 #判断k1中是否包含v1,1:有 
(integer) 1 
127.0.0.1:6379> sismember k1 v5 #判断k1中是否包含v5,0:无 
(integer) 0
  1. scard

返回集合中元素的个数。当 key 不存在时,返回 0 。

scard <key>

示例

127.0.0.1:6379> sadd k1 v1 v2 v1 v3 v2 
(integer) 3 
127.0.0.1:6379> scard k1 
(integer) 3
  1. srem

删除多个元素

srem key member [member ...]

移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。当 key 不是集合类型,返回一个错误。

返回值:被成功移除的元素的数量,不包括被忽略的元素。

示例

127.0.0.1:6379> sadd course java c c++ python #集合course中添加4个元素
(integer) 4 
127.0.0.1:6379> smembers course #获取course集合所有元素 
1) "python" 
2) "java" 
3) "c++" 
4) "c" 
127.0.0.1:6379> srem course java c #删除course集合中的java和c 
(integer) 2 
127.0.0.1:6379> smembers course #获取course集合所有元素,剩下2个了 
1) "python"
2) "c++"
  1. spop

随机弹出多个值

spop <key> <count>

随机从key集合中弹出count个元素,count默认值为1

返回值:被移除的随机元素。当 key 不存在或 key 是空集时,返回 nil

示例

127.0.0.1:6379> sadd course java c c++ python #course集合中添加4个元素
(integer) 4
127.0.0.1:6379> smembers course #获取course集合中所有元素
1) "python"
2) "java"
3) "c++"
4) "c"
127.0.0.1:6379> spop course #随机弹出1个元素,被弹出的元素会被删除
"c++"
127.0.0.1:6379> spop course 2 #随机弹出2个元素
1) "java"
2) "python"
127.0.0.1:6379> smembers course #输出剩下的元素 
1) "c"
  1. srandmember

随机获取多个元素,不会从集合中删除

srandmember <key> <count>

从key指定的集合中随机返回count个元素,count可以不指定,默认值是1。

srandmember **spop****的区别:**都可以随机获取多个元素,srandmember 不会删除元素,而spop会删除元素。

返回值**😗*只提供 key 参数时,返回一个元素;如果集合为空,返回 nil 。如果提供了 count 参数,那么返回一个数组;如果集合为空,返回空数组。

示例

127.0.0.1:6379> sadd course java c c++ python #course中放入5个元素
(integer) 4 
127.0.0.1:6379> smembers course #输出course集合中所有元素 
1) "python" 2) "java" 3) "c++" 4) "c" 
127.0.0.1:6379> srandmember course 3 #随机获取3个元素,元素并不会被删除
1) "python" 2) "c++" 3) "c" 
127.0.0.1:6379> smembers course #输出course集合中所有元素,元素个数未变 
1) "python" 2) "java" 3) "c++" 4) "c"
  1. smove

将某个原创从一个集合移动到另一个集合。是原子性操作。

smove <source> <destination> member

将 member 元素从 source 集合移动到 destination 集合。

如果 source 集合不存在或不包含指定的 member 元素,则 smove 命令不执行任何操作,仅返回 0 。否则, member 元素从 source 集合中被移除,并添加到 destination 集合中去。

当 destination 集合已经包含 member 元素时,smove 命令只是简单地将 source 集合中的member 元素删除。

当 source 或 destination 不是集合类型时,返回一个错误。

返回值:如果 member 元素被成功移除,返回 1 。如果 member 元素不是 source 集合的成员,并且没有任何操作对 destination 集合执行,那么返回 0 。

示例

127.0.0.1:6379> sadd course1 java php js #集合course1中放入3个元素[java,php,js] 
(integer) 3 
127.0.0.1:6379> sadd course2 c c++ #集合course2中放入2个元素[c,c++] 
(integer) 2 
127.0.0.1:6379> smove course1 course2 js #将course1中的js移动到course2 
(integer) 1 
127.0.0.1:6379> smembers course1 #输出course1中的元素 
1) "java" 2) "php" 
127.0.0.1:6379> smembers course2 #输出course2中的元素 
1) "js" 2) "c++" 3) "c"
  1. sinter

取多个集合的交集

sinter key [key ...]

示例

127.0.0.1:6379> sadd course1 java php js #集合course1:[java,php,js] 
(integer) 3 
127.0.0.1:6379> sadd course2 c c++ js #集合course2:[c,c++,js]
(integer) 3 
127.0.0.1:6379> sadd course3 js html #集合course3:[js,html] 
(integer) 2 
127.0.0.1:6379> sinter course1 course2 course3 #返回三个集合的交集,只有:[js] 
1) "js"
  1. sinterstore

将多个集合的交集放到一个新的集合中

sinterstore destination key [key ...]

这个命令类似于 sinter 命令,但它将结果保存到 destination 集合,而不是简单地返回结果

集。

返回值:结果集中的成员数量。

  1. sunion

取多个集合的并集,自动去重

sunion key [key ...]

示例

127.0.0.1:6379> sadd course1 java php js #集合course1:[java,php,js]
(integer) 3 
127.0.0.1:6379> sadd course2 c c++ js #集合course2:[c,c++,js] 
(integer) 3
127.0.0.1:6379> sadd course3 js html #集合course3:[js,html] 
(integer) 2
127.0.0.1:6379> sunion course1 course2 course3 #返回3个集合的并集,会自动去重 
1) "php" 2) "js" 3) "java" 4) "html" 5) "c++" 6) "c"
  1. sunionstore

将多个集合的并集放到一个新的集合中

sinterstore destination key [key ...]

这个命令类似于 sunion 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集。

返回值:结果集中的成员数量。

  1. sdiff

取多个集合的差集

SDIFF key [key ...]

返回一个集合的全部成员,该集合是所有给定集合之间的差集。不存在的 key 被视为空集。

示例

127.0.0.1:6379> sadd course1 java php js #集合course1:[java,php,js] 
(integer) 3
127.0.0.1:6379> sadd course2 c c++ js #集合course2:[c,c++,js] 
(integer) 3 
127.0.0.1:6379> sadd course3 js html #集合course3:[js,html] 
(integer) 2
127.0.0.1:6379> sdiff course1 course2 course3 #返回course1中有的而course2和course3 中都没有的元素 
1) "java" 2) "php"
  1. sdiffstore

将多个集合的差集放到一个新的集合中

sdiffstore destination key [key ...]

这个命令类似于 sdiff 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集。

返回值: 结果集中的成员数量。

数据结构

set数据结构是字典,字典是用hash表实现的。

Java中的HashSet的内部实现使用HashMap,只不过所有的value都指向同一个对象。

Redis的set结构也是一样的,它的内部也使用hash结构,所有的value都指向同一个内部值。

哈希(Hash)

简介

Redis hash是一个键值对集合。

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

类似于java里面的Map<String,Object>

常用命令

  1. hset

设置多个field的值

hset key field value [field value ...]

将哈希表 key 中的域 field 的值设为 value 。如果 key 不存在,一个新的哈希表被创建并进行 hset 操作。如果域 field 已经存在于哈希表中,旧值将被覆盖。

**返回值:**如果 field 是哈希表中的一个新建域,并且值设置成功,返回 1 。如果哈希表中域 field 已经存在且旧值已被新值覆盖,返回 0 。

示例

127.0.0.1:6379> hset user name ready age 30 #哈希表user中设置2个域:name和age,name的 值为ready,age的值为30 
(integer) 2
  1. hget

获取指定filed的值

hget key field

示例

127.0.0.1:6379> hset user name ready age 30 #哈希表user中设置2个域:name和age,name的 值为ready,age的值为30 
(integer) 2 127.0.0.1:6379> hget user name #获取user中的name 
"ready"
  1. hgetall

返回hash表所有的域和值

hgetall key

示例

127.0.0.1:6379> hset user name ready age 30 #哈希表user中设置2个域:name和age,name的 值为ready,age的值为30 
(integer) 2 
127.0.0.1:6379> hgetall user #获取user所有信息
1) "name" 
2) "ready"
3) "age" 
4) "30"
  1. hmset

和hset类似(已弃用)

hmset key field value [field value ...]
  1. hexists

判断给定的field是否存在,1:存在,0:不存在

hexists key field

查看哈希表 key 中,给定域 field 是否存在。

**返回值:**如果哈希表含有给定域,返回 1 。如果哈希表不含有给定域,或 key 不存在,返回 0 。

示例

127.0.0.1:6379> hset user name ready age 30 #哈希表user中设置2个域:name和age,name的 值为ready,age的值为30 
(integer) 2 
127.0.0.1:6379> hexists user name #user中存在name域
(integer) 1 
127.0.0.1:6379> hexists user address #user中不存在address域,返回0 
(integer) 0 
127.0.0.1:6379> hexists user1 address #user1这个key不存在,返回0
(integer) 0
  1. hkeys

列出所有的filed

127.0.0.1:6379> hset user name ready age 30 #哈希表user中设置2个域:name和age,name的 值为ready,age的值为30 
(integer) 2 
127.0.0.1:6379> hkeys user #获取user中的所有filed 
1) "name" 
2) "age"
  1. hvals

列出所有的value

127.0.0.1:6379> hset user name ready age 30 #哈希表user中设置2个域:name和age,name的 值为ready,age的值为30
(integer) 2
127.0.0.1:6379> hvals user #获取user中的所有filed的值列表
1) "ready" 2) "30"
  1. hlen

返回filed的数量,当 key 不存在时,返回 0 。

127.0.0.1:6379> hset user name ready age 30 #哈希表user中设置2个域:name和age,name的 值为ready,age的值为30 
(integer) 2 
127.0.0.1:6379> hlen user 
(integer) 2
  1. hincrby

filed的值加上指定的增量

hincrby key field increment

为哈希表 key 中的域 field 的值加上增量 increment 。
增量也可以为负数,相当于对给定域进行减法操作。
如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。
如果域 field 不存在,那么在执行命令前,域的值被初始化为 0 。
对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误。

返回值:

执行 hincrby 命令之后,哈希表 key 中域 field 的值。

示例

127.0.0.1:6379> hset siteInfo site itsoku.com pv 1000 #hash表siteInfo中有2个域: {site:"itsoku.com",pv:1000} 
(integer) 2 
127.0.0.1:6379> hget siteInfo pv #获取siteInfo中pv的值 
"1000" 127.0.0.1:6379> hincrby siteInfo pv 10 #siteInfo中的pv值增加10 
(integer) 1010 
127.0.0.1:6379> hget siteInfo pv #获取siteInfo中的pv 
"1010" 
127.0.0.1:6379> hincrby siteInfo uv 500 #siteInfo中的uv值增加500,uv这个域不存在,则会 先添加,然后再执行hincrby
(integer) 500
  1. hsetnx

当filed不存在的时候,设置filed的值

hsetnx key field value

将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在。若域 field 已经存在,该操作无效。如果 key 不存在,一个新哈希表被创建并执行 hsetnx 命令。

**返回值:**设置成功,返回 1 。如果给定域已经存在且没有操作被执行,返回 0 。

示例:

127.0.0.1:6379> hset user name ready age 30 #创建user,包含2个域:name、age 
(integer) 2 
127.0.0.1:6379> hsetnx user name tom #name已存在,设置失败,返回0 
(integer) 0 
127.0.0.1:6379> hget user name #name依旧是ready 
"ready" 
127.0.0.1:6379> hsetnx user address shanghai #address不存在,设置成功
(integer) 1 
127.0.0.1:6379> hget user address #输出address的值 
"shanghai"

数据结构

Hash类型对应的数据结构是2中:ziplist(压缩列表),hashtable(哈希表)。

当field-value长度较短个数较少时,使用ziplist,否则使用hashtable。

有序集合zset

简介

redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。

不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。

集合的成员是唯一的,但是评分是可以重复的。

因为元素是有序的,所以你可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。

访问有序集合中的中间元素也是非常快的,因为你能够使用有序集合作为一个没有重复成员你的智能列表。

常用命令

  1. zadd

添加元素

zadd <key> <score1> <member1> <score2> <member2> ...

将一个或多个 member 元素及其 score 值加入到有序集 key 当中。

如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。

score 值可以是整数值或双精度浮点数。

如果 key 不存在,则创建一个空的有序集并执行 zadd 操作。当 key 存在但不是有序集类型时,返回一个错误。

返回值:被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。

示例

127.0.0.1:6379> zadd topn 100 java 80 c 90 c++ 50 php 70 js #创建名称为topn的zset, 添加了5个元素 
(integer) 5
  1. zrange

score升序,获取指定索引范围的元素

zrange key start top [withscores]
  • 返回存储在有序集合 key 中的指定范围的元素。 返回的元素可以认为是按score从最低到最高排列,如果得分相同,将按字典排序。
  • 下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
  • zrange key 0 -1:可以获取所有元素
  • withscores:让成员和它的 score 值一并返回,返回列表以 value1,score1, …, valueN,scoreN 的格式表示

可用版本:>= 1.2.0

时间复杂度😮(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。

返回值:指定区间内,带有 score 值(可选)的有序集成员的列表。

示例

127.0.0.1:6379> zadd topn 100 java 80 c 90 c++ 50 php 70 js #创建名称为topn的zset, 添加了5个元素
(integer) 5 
127.0.0.1:6379> zrange topn 0 -1 #按score升序,返回topn中所有元素的值 
1) "php" 2) "js" 3) "c" 4) "c++" 5) "java" 
127.0.0.1:6379> zrange topn 0 -1 withscores #按score升序,返回所有元素的值以及score 
1) "php" 
2) "50" 
3) "js" 
4) "70" 
5) "c" 
6) "80" 
7) "c++" 
8) "90" 
9) "java" 
10) "100" 
127.0.0.1:6379> zrange topn 2 4 #返回索引范围[2,4]内的3个元素
1) "c"
2) "c++"
3) "java"
  1. zrevrange

score降序,获取指定索引范围的元素

zrevrange key start stop [WITHSCORES]
  • 返回存储在有序集合 key 中的指定范围的元素。 返回的元素可以认为是按score最高到最低排列, 如果得分相同,将按字典排序。
  • 下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
  • withscores:让成员和它的 score 值一并返回,返回列表以 value1,score1, …, valueN,scoreN 的格式表示

示例

127.0.0.1:6379> zadd topn 100 java 80 c 90 c++ 50 php 70 js #创建名称为topn的zset, 添加了5个元素 
(integer) 5 
127.0.0.1:6379> zrevrange topn 0 -1 #按照score降序获取所有元素 
1) "java" 
2) "c++"
3) "c" 
4) "js" 
5) "php" 
127.0.0.1:6379> zrevrange topn 0 2 #按照score降序获取前3名 
1) "java"
2) "c++" 
3) "c"
  1. zrangebyscore

按照score升序,返回指定score范围内的数据

zrangebyscore key min max [WITHSCORES] [LIMIT offset count]

返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。

具有相同 score 值的成员按字典序来排列(该属性是有序集提供的,不需要额外的计算)。

可选的 LIMIT 参数指定返回结果的数量及区间(就像SQL中的 SELECT LIMIT offset, count ),注意当 offset 很大时,定位 offset 的操作可能需要遍历整个有序集,此过程最坏复杂度为O(N) 时间。

可选的 WITHSCORES 参数决定结果集是单单返回有序集的成员,还是将有序集成员及其 score值一起返回。

示例

127.0.0.1:6379> zadd topn 100 java 80 c 90 c++ 50 php 70 js #创建名称为topn的zset, 添加了5个元素 
(integer) 5
127.0.0.1:6379> zrangebyscore topn 70 90 #score升序,获取score位于[70,90]区间中的元素 值
1) "js" 2) "c" 3) "c++" 
127.0.0.1:6379> zrangebyscore topn 70 90 withscores #score升序,获取score位于 [70,90]区间中的元素值及score 
1) "js" 2) "70" 3) "c" 4) "80" 5) "c++" 6) "90" 
127.0.0.1:6379> zrangebyscore topn 70 90 withscores limit 1 2 #相当于:select value,score from topn集合 where score>=70 and score<=90 order by score asc limit 1,2
1) "c" 2) "80" 3) "c++" 4) "90"
  1. zrevrangebyscore

按照score降序,返回指定score范围内的数据

zrevrangebyscore key max min [WITHSCORES] [LIMIT offset count]

返回有序集 key 中, score 值介于 max 和 min 之间(默认包括等于 max 或 min )的所有的成员。有序集成员按 score 值递减(从大到小)的次序排列。具有相同 score 值的成员按字典序的逆序排列。

除了成员按 score 值递减的次序排列这一点外, zrevrangebyscore 命令的其他方面和zrangebyscore 命令一样。

示例

127.0.0.1:6379> zadd topn 100 java 80 c 90 c++ 50 php 70 js #创建名称为topn的zset, 添加了5个元素 
(integer) 5
127.0.0.1:6379> zrevrangebyscore topn 100 90 #score降序,获取score位于[70,90]区间中 的元素值 
1) "java" 2) "c++" 
127.0.0.1:6379> zrevrangebyscore topn 100 90 withscores #score降序,获取score位于 [70,90]区间中的元素值及score 
1) "java" 2) "100" 3) "c++" 4) "90"
  1. zincrby

为指定元素的score加上指定的增量

zincrby key increment member

为有序集 key 的成员 member 的 score 值加上增量 increment 。

可以通过传递一个负数值 increment ,让 score 减去相应的值,比如 ZINCRBY key -5 member ,就是让 member 的 score 值减去 5 。

当 key 不存在,或 member 不是 key 的成员时, ZINCRBY key increment member 等同于ZADD key increment member 。

当 key 不是有序集类型时,返回一个错误。

score 值可以是整数值或双精度浮点数。

示例

127.0.0.1:6379> zadd topx 90 java 70 c 80 c++ #集合topx中添加3个元素:java、c、c++,
对应的score分别是:90、70、80
(integer) 3
127.0.0.1:6379> zrevrange topx 0 -1 withscores #输出集合topx中的元素,包含score
1) "java"
2) "90"
3) "c++"
4) "80"
5) "c"
6) "70"
127.0.0.1:6379> zincrby topx 5 java #对topx中的元素java的score加5,变成95了
"95"
127.0.0.1:6379> zrevrange topx 0 -1 withscores # 输出集合元素,注意java的score是95了 
1) "java"
2) "95" 
3) "c++" 
4) "80" 
5) "c" 
6) "70"
  1. zrem

删除集合中多个元素

zrem key member [member ...]

移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。
当 key 存在但不是有序集类型时,返回一个错误。

示例

127.0.0.1:6379> zadd topx 90 java 70 c 80 c++ #集合topx中添加3个元素:java、c、c++, 对应的score分别是:90、70、80 
(integer) 3 
127.0.0.1:6379> zrange topx 0 -1 #输出集合topx中所有元素 
1) "c" 2) "c++" 3) "java" 
127.0.0.1:6379> zrem topx c c++ #删除集合topx中的2个元素:c、c++ 
(integer) 2
127.0.0.1:6379> zrange topx 0 -1 #输出集合topx中所有元素 
1) "java"
  1. zremrangebyrank

根据索引范围删除元素

zremrangebyrank key start stop

移除有序集 key 中,指定排名(rank)区间内的所有成员。

区间分别以下标参数 start 和 stop 指出,包含 start 和 stop 在内。下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。

也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。

示例

127.0.0.1:6379> zadd topx 90 java 70 c 80 c++ #集合topx中添加3个元素:java、c、c++, 对应的score分别是:90、70、80 
(integer) 3 
127.0.0.1:6379> zrange topx 0 -1 #输出集合topx中所有元素
1) "c" 2) "c++" 3) "java"
127.0.0.1:6379> zremrangebyrank topx 0 1 #删除索引范围[0,1]的数据 
(integer) 2 
127.0.0.1:6379> zrange topx 0 -1 #输出鞂topx中所有元素 
1) "java"
  1. zremrangebyscore

根据score的范围删除元素

zremrangebyscore key min max

移除有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员

示例

127.0.0.1:6379> zadd topx 90 java 70 c 80 c++ 50 php #topx集合中添加4个元素
(integer) 4 
127.0.0.1:6379> zrange topx 0 -1 withscores #输出topx中所有元素值、score 
1) "php" 2) "50" 3) "c" 4) "70" 5) "c++" 6) "80" 7) "java" 8) "90" 
127.0.0.1:6379> zremrangebyscore topx 70 80 #删除score位于[70,80]区间的元素 
(integer) 2 
127.0.0.1:6379> zrange topx 0 -1 withscores #输出剩下的元素
1) "php" 2) "50" 3) "java" 4) "90"
  1. zcount

统计指定score范围内元素的个数

zcount key min max

返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量

示例

127.0.0.1:6379> zadd topx 90 java 70 c 80 c++ 50 php #topx集合中添加4个元素
(integer) 4 
127.0.0.1:6379> zcount topx 80 100 #统计score位于[80,100]区间中的元素个数
(integer) 2
  1. zrank

按照score升序,返回某个元素在集合中的排名

zrank key member

返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。

排名以 0 为底,也就是说, score 值最小的成员排名为 0 。

示例

127.0.0.1:6379> zadd topx 90 java 70 c 80 c++ 50 php #topx集合中添加4个元素 
(integer) 4 
127.0.0.1:6379> zrank topx c #获取元素c的排名,返回1表示排名第2 
(integer) 1 127.0.0.1:6379> zrange topx 0 -1 #输出集合中所有元素,看一下c的位置确实是2
1) "php" 2) "c" 3) "c++" 4) "java"
  1. zrevrank

按照score降序,返回某个元素在集合中的排名

返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。排名以 0 为底,也就是说, score 值最大的成员排名为 0 。

示例

127.0.0.1:6379> zadd topx 90 java 70 c 80 c++ 50 php #topx集合中添加4个元素 
(integer) 4 
127.0.0.1:6379> zrange topx 0 -1 
1) "php" 2) "c" 3) "c++" 4) "java" 
127.0.0.1:6379> zrevrank topx java #score降序,得到java的排名,排在第1位 
(integer) 0
  1. zscore

返回集合中指定元素的score

zscore key member

返回有序集 key 中,成员 member 的 score 值。
如果 member 元素不是有序集 key 的成员,或 key 不存在,返回 nil 。

示例

127.0.0.1:6379> zadd topx 90 java 70 c 80 c++ 50 php #topx集合中添加4个元素
(integer) 4 
127.0.0.1:6379> zrange topx 0 -1 #输出topx集合所有元素 
1) "php" 2) "c" 3) "c++" 4) "java"
127.0.0.1:6379> zscore topx java #获取集合topx中java的score 
"90"

数据结构

SortedSet(zset)是redis提供的一个非常特别的数据结构,内部使用到了2种数据结构。

1、hash表

类似于java中的Map<String,score>,key为集合中的元素,value为元素对应的score,可以用来快速定

位元素定义的score,时间复杂度为O(1)

2、跳表

跳表(skiplist)是一个非常优秀的数据结构,实现简单,插入、删除、查找的复杂度均为O(logN)。

类似java中的ConcurrentSkipListSet,根据score的值排序后生成的一个跳表,可以快速按照位置的顺序或者score的顺序查询元素。

这里我们来看一下跳表的原理。

首先从考虑一个有序表开始:

在这里插入图片描述

从该有序表中搜索元素 < 23, 43, 59 > ,需要比较的次数分别为 < 2, 4, 6 >,总共比较的次数为 2 + 4 + 6= 12 次。有没有优化的算法吗? 链表是有序的,但不能使用二分查找。类似二叉搜索树,我们把一些节点提取出来,作为索引。得到如下结构:

在这里插入图片描述

这里我们把 < 14, 34, 50, 72 > 提取出来作为一级索引,这样搜索的时候就可以减少比较次数了。我们还可以再从一级索引提取一些元素出来,作为二级索引,变成如下结构:
在这里插入图片描述

这里元素不多,体现不出优势,如果元素足够多,这种索引结构就能体现出优势来了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/149909.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于安卓android微信小程序的装修家装小程序

项目介绍 巧匠家装小程序的设计主要是对系统所要实现的功能进行详细考虑&#xff0c;确定所要实现的功能后进行界面的设计&#xff0c;在这中间还要考虑如何可以更好的将功能及页面进行很好的结合&#xff0c;方便用户可以很容易明了的找到自己所需要的信息&#xff0c;还有系…

SOLIDWORKS Flow Simulation阀门内流体仿真

Flow Simulation 导读 阀门作为输送系统中的控制设备其主要功能是接通管路中的流体介质,又或是调节流体的流量、压力等&#xff0c;在阀门的设计中&#xff0c;流量系数Cv,Kv&#xff0c;以及流阻系数都是基本参数&#xff0c;本节将讲解通过SOLIDWORKS Flow Simulation在三维…

lxml基本使用

lxml是python的一个解析库&#xff0c;支持HTML和XML的解析&#xff0c;支持XPath解析方式&#xff0c;而且解析效率非常高 XPath&#xff0c;全称XML Path Language&#xff0c;即XML路径语言&#xff0c;它是一门在XML文档中查找信息的语言&#xff0c;它最初是用来搜寻XML文…

Netty实战专栏 | NIO详解

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Netty实战专栏 ✨特色专栏&#xff1a…

C语言之深入指针(二)(详细教程)

C语言之深入指针 文章目录 C语言之深入指针1. 传值调用和传址调用2. 数组名的理解3. 使用指针访问数组3. ⼀维数组传参的本质 1. 传值调用和传址调用 写一个函数用来交换a b的值 传值调用&#xff1a; #include <stdio.h> void Swap1(int x, int y) {int tmp 0;tmp x;…

第十八章 Swing程序设计

Swing用于开发桌面窗体程序&#xff0c;是JDK的第二代GUI框架&#xff0c;其功能比JDK第一代GUI框架AWT更为强大、性能更加优良。但因为Swing技术推出时间太早&#xff0c;其性能、开发效率等不及一些其他流行技术&#xff0c;所以目前市场上大多数桌面窗体程序都不是由Java开发…

rabbitmq 集群搭建

RabbitMQ集群介绍 RabbitMQ集群是一组RabbitMQ节点&#xff08;broker&#xff09;的集合&#xff0c;它们一起工作以提供高可用性和可伸缩性服务。 RabbitMQ集群中的节点可以在同一物理服务器或不同的物理服务器上运行。 RabbitMQ集群的工作原理是&#xff0c;每个节点在一个…

12-使用vue2实现todolist待办事项

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…

Python杂谈--关于iter迭代器的一些讨论

首先我们来看下面一段代码&#xff1a; for i in range(5):print(i) 这是一段非常简单的代码&#xff0c;它会打印出“0-5”这五个数字。 此时在range()迭代器中&#xff0c;它的start为空(默认为无穷小)&#xff0c;stop为5&#xff0c;step为空(默认为1)。 此时我们在看下…

hidl hwbinder和binder混合使用相关的joinThreadPool问题解答

背景&#xff1a; 今天一个学员在群里有个提问如下图&#xff0c;怎么有两个joinThread&#xff0c;会执行么&#xff1f;joinThread不是死循环等待数据吗&#xff1f; /frameworks/av/media/mediaserver/main_mediaserver.cpp 当开始看到这个时候确实也觉得最后的hw的join根本…

电脑篇——将串口映射到远程电脑上

通过Windows自带的远程桌面连接功能&#xff0c;可以通过修改本地资源选项&#xff0c;将本机的串口/端口映射到远程电脑上。 即可将端口映射到远程电脑上。 &#xff08;在远程的电脑的设备管理器中可能不会显示&#xff0c;但是用串口调试相关的工具&#xff0c;是可以找到相…

JVM——类加载器(JDK8及之前,双亲委派机制)

目录 1.类加载器的分类1.实现方式分类1.虚拟机底层实现2.JDK中默认提供或者自定义 2.类加载器的分类-启动类加载器3.类加载器的分类-Java中的默认类加载器4.类加载器的分类-扩展类加载器5.类加载器的分类-类加载器的继承 2.类加载器的双亲委派机制 类加载器&#xff08;ClassLo…

文件上传_白名单、内容校验、竞争上传

服务端校验—后缀名白名单校验 服务端校验—文件内容头校验 竞争上传

ROS 学习应用篇(五)服务Server学习之自定义服务与调用

在之前我学着如何建立一个话题Topic的消息类型&#xff0c;那时候建立了一个msg文件&#xff0c;包括&#xff0c;消息名称和消息数据类型&#xff08;int还是什么之类的。&#xff09;&#xff0c;将其链接到CMakeList&#xff0c;.xml文件补录需要的依赖&#xff0c;CMakeLis…

十九章总结

一.Java绘图类 1.Graphics类 Graphics类是所有图形上下文的抽象基类&#xff0c;它允许应用程序在组件以及闭屏图像上进行绘制。Graphics类封装了Java支持的基本绘图操作所需的状态信息&#xff0c;主要包括颜色、字体、画笔、文本、图像等。 2.Graphics2D类 Graphics2…

Vue3问题:如何实现拼图验证+邮箱登录功能?前后端!

前端功能问题系列文章&#xff0c;点击上方合集↑ 序言 大家好&#xff0c;我是大澈&#xff01; 本文约3500字&#xff0c;整篇阅读大约需要5分钟。 本文主要内容分三部分&#xff0c;第一部分是需求分析&#xff0c;第二部分是实现步骤&#xff0c;第三部分是问题详解。 …

「软件设计」权威领域驱动设计(DDD)简介

「软件设计」权威领域驱动设计(DDD)简介 今天的企业应用程序无疑是复杂的&#xff0c;并依赖一些专门技术&#xff08;持久性&#xff0c;AJAX&#xff0c;Web服务等&#xff09;来完成它们的工作。作为开发人员&#xff0c;我们倾向于关注这些技术细节是可以理解的。但事实是…

一键将CSDN博客文章如何转为Markdown

文章目录 1.在CSDN博文页面点击右键&#xff0c;选择“检查”&#xff08;Google浏览器为例&#xff09;。2.在查看器中搜索article_content&#xff0c;找到对应内容&#xff0c;点击…复制为outerHTML。3.打开网址https://tool.lu/markdown/&#xff0c;点击HTML2MD&#xff…

准备搞OpenStack了,先装一台最新的Ubuntu 23.10

正文共&#xff1a;1113 字 25 图&#xff0c;预估阅读时间&#xff1a;2 分钟 依稀记得前面发了一篇Ubuntu的安装文档&#xff08;66%的经验丰富开发者和69%的学生更喜欢的Ubuntu的安装初体验&#xff09;&#xff0c;当时安装的是20.04.3的版本&#xff0c;现在看来已经是非常…