【Redis7】--2.十大数据类型

news2024/11/19 9:25:24

文章目录

  • Redis十大数据类型
    • 1.Key通用命令
      • 1.1keys *
      • 1.2EXISTS
      • 1.3DEL
      • 1.4EXPIRE
      • 1.5TTL
      • 1.6TYPE
      • 1.7DBSIZE
      • 1.8SELECT
      • 1.9MOVE
      • 1.10FLUSHDB
      • 1.11FLUSHALL
      • 1.12help
      • 1.13CONFIG
    • 2.Redis十大数据类型
      • 2.1String
        • 2.1.1SET和GET
        • 2.1.2MSET和MGET
        • 2.1.3INCR、INCRBY
        • 2.1.4SETNX和SETEX
        • 2.1.5MSETNX
        • 2.1.6SETRANGE和GETRANGE
        • 2.1.7STRLEN
        • 2.1.8APPEND
        • 2.1.9GETSET
        • 2.1.10key的结构
        • 2.1.11应用场景
      • 2.2List
        • 2.2.1LPUSH和RPUSH
        • 2.2.2LPUSHX和RPUSHX
        • 2.2.3LRANGE
        • 2.2.4LPOP和RPOP
        • 2.2.5BLPOP和BRPOP
        • 2.2.6RPOPLPUSH
        • 2.2.7LINDEX
        • 2.2.8LLEN
        • 2.2.9LREM
        • 2.2.10LTRIM
        • 2.2.11LSET
        • 2.2.12LINSERT
        • 2.2.13应用场景
      • 2.3HASH
        • 2.3.1HSET和HGET
        • 2.3.2HMSET和HMGET
        • 2.3.3HGETALL
        • 2.3.4HDEL
        • 2.3.5HLEN
        • 2.3.6HEXISTS
        • 2.3.7HKEYS和HVALS
        • 2.3.8HINCR、HINCRBYFLOAT
        • 2.3.9HSETNX
        • 2.3.10 应用场景
      • 2.4Set
        • 2.4.1SADD
        • 2.4.2SMEMBERS
        • 2.4.3 SISMEMBER
        • 2.4.4SCARD
        • 2.4.5SREM
        • 2.4.6SRANDMEMBER
        • 2.4.7SPOP
        • 2.4.8 SMOVE
        • 2.4.9集合运算
        • 2.4.10应用场景
      • 2.5SortedSet
        • 2.5.1ZADD
        • 2.5.2ZCARD
        • 2.5.3ZCOUNT
        • 2.5.4ZSCORE
        • 2.5.5ZRANGE和ZREVRANGE
        • 2.5.6ZRANGEBYSCORE和ZREVRANGEBYSCORE
        • 2.5.7ZRANK和ZREVRANK
        • 2.5.8ZREM
        • 2.5.9ZINCRBY
        • 2.5.10ZPOPMAX和ZPOPMIN
        • 2.5.11ZMPOP
        • 2.5.12集合运算
        • 2.5.13应用场景
      • 2.6Bitmap
        • 2.6.1SETBIT
        • 2.6.2GETBIT
        • 2.6.3BITCOUNT
        • 2.6.4BITOP
        • 2.6.5应用场景
      • 2.7HyperLogLog
        • 2.7.1PFADD
        • 2.7.2PFCOUNT
        • 2.7.3PFMERGE
      • 2.8Geospatial
        • 2.8.1GEOADD
        • 2.8.2GEOPOS
        • 2.8.3GEOHASH
        • 2.8.4GEODIST
        • 2.8.5GEORADIUS
        • 2.8.6GEORADIUSBYMEMBER
      • 2.9Stream
        • 2.9.1XADD
        • 2.9.2XRANGE
        • 2.9.3 XREVRANGE
        • 2.9.4XDEL
        • 2.9.5 XLEN
        • 2.9.6XTRIM
        • 2.9.7XREAD
        • 2.9.8XGROUP
        • 2.9.9XREADGROUP
        • 2.9.10XPENDING
        • 2.9.11XACK
        • 2.9.12XINFO
      • 2.10Bitfield
        • 2.10.1BITFIELD

Redis十大数据类型

redis常见数据类型操作命令官网:

  • 中文:http://www.redis.cn/commands.html
  • 英文:https://redis.io/commands/

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

1.Key通用命令

redis命令不区分大小写,但是key是区分大小写的。没有返回值的命令执行成功返回1,失败返回0

1.1keys *

查看当前库所有的key

image-20230909173839320

1.2EXISTS

EXISTS key [key ...]:返回给定的key中已存在的个数,一个都不存在返回0。

image-20230909173914053

1.3DEL

del key [key ...]:删除给定的key,返回值为删除的个数

image-20230909173943472

1.4EXPIRE

expire key second:给key设置一个过期时间second,单位为秒,比如expire name 10,表示name这个键10秒后过期

1.5TTL

ttl key:查看key的过期时间,不设置过期时间的话默认是永不过期(返回值-1),过期则返回-2。time to live的缩写。

image-20230909174032465

1.6TYPE

type key:返回key的类型,如果key不存在返回null

image-20230909174055815

1.7DBSIZE

查看当前数据库有多少个key

1.8SELECT

【0-15】一个redis默认有16个数据库,对应索引为0~15,默认在0号数据库,可以去redis.conf的文件,搜索database,找到配置,可以更改初始多少个库

select index:切换数据库,redis默认一共16个数据库,对应索引为0~15,默认的数据库是0号库

1.9MOVE

【0-15】一个redis默认有16个数据库,默认在0号数据库

move key dbindex:将指定key移入指定数据库中

image-20230909174439174

1.10FLUSHDB

清空当前库的key

flushdb		# 输入fushdb回车即可清空当前库的所有键,此操作慎用

1.11FLUSHALL

清空所有库的key

flushall	# 输入flushall会清空所有库的键,此操作慎用

1.12help

help命令可以查看redis命令或数据类型的使用说明,注意该命令要在redis客户端才能使用。

  • help命令:查看命令的使用说明

image-20230909174735597

  • help @数据类型:查看redis数据类型的使用说明

image-20230909174843719

1.13CONFIG

查看配置文件指定信息

127.0.0.1:6379> CONFIG get dir			# 查看RDB文件存放目录
127.0.0.1:6379> CONFIG get save			# 查看RDB触发条件
127.0.0.1:6379> CONFIG get appendonly	# 查看AOF是否开启

2.Redis十大数据类型

redis中的数据都是用k-v键值对存储的,所有的key都是String类型,所说的十大数据类型指的是value值的数据类型。

准确来说这十大数据类型只有六大数据类型,分别是String、List、Hash、Set、Zset、Stream。
其余的四种是对这数据类型封装出来的数据结构,分别是Bitmap(String)、HyperLogLog(String)、Geospatial(Zset)、BitField(String)。

2.1String

字符串

String类型,也就是字符串类型,是Redis中最简单的存储类型,单key单value结构

其value是字符串,不过根据字符串的格式不同,又可以分为3类:

  • String:普通字符串
  • int:整数类型,可以做自增、自减操作
  • float:浮点类型,可以做自增、自减操作

不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同。字符串类型的最大空间不能超过512m

String类型的常用命令:

2.1.1SET和GET

set key value [可选参数]:添加或者修改一个String类型的键值对

get key:根据key获取String类型的value,不存在返回nil

可选参数:

  • EX:以秒为单位设置过期时间

  • PX:以毫秒为单位设置过期时间

  • EXAT:设置以秒为单位的时间戳为过期时间

  • PXAT:设置以毫秒为单位的时间戳为过期时间

  • NX:键不存在的时候添加键值对,存在返回nil

  • XX:键存在的时候设置键值,也就是覆盖,不存在返回nil

  • GET:返回指定键原本的值,若不存在返回nil

  • KEEPTTL:保留键之前的生存时间,即在覆盖键值时过期时间还是之前的过期时间

    提示:set命令使用EX、PX、NX参数,效果等同于SETEX、SETNX

NX/XX是互斥的,但是不写则是并集,即不写时总是会设置,默认是键不存在就创建键值,键存在就覆盖

set name Tom	# 设置name=Tom
set name Bob get # 重新设置name值并返回原来的name值
set name Bob ex 20 get # 重新设置name值并设置过期时间20秒,并返回之前的name值
get name	# 获取name的值

image-20230910092452749

set name Marry keepttl	# 表示保持之前的过期时间

image-20230910092903509

set name Mike XX	# name已存在时才创建(覆盖)
set name Mike NX	# name不存在时创建,已存在时不创建

image-20230910093126762

set name Mike EXAT 1680715582	# 设置以秒为单位的时间戳的过期时间
set name Mike PXAT 1680715582123	# 设置以毫秒为单位的时间戳的过期时间

unix时间戳很少用到,这里java中可以通过如下方式获得

System.out.println(Long.toString(System.currentTimeMillis() / 1000L));   

2.1.2MSET和MGET

M是multi的缩写,表示多个的意思。
这里的命令类似事务,要么都成功,要么都失败
这里可以不加空格紧跟NX或XX

mset key value [key value ...]:批量添加多个String类型的键值对

mset name Tom age 18 sex man	# 设置name=Tom,age=18,sex=man

mget key [key ...]:批量获取String类型的value

mget name age sex	# 获取name、age、sex的值

image-20230910093408148

2.1.3INCR、INCRBY

increase的缩写,表示自增

incr key:让一个整型的key自增1

set age 20
incr age	# 让age自增1

image-20230910093535211

incrby key step:指定步长step,让一个整型的key自增step

incrby age 2	# 让age自增2

image-20230910093625383

incrbyfloat key step:让一个浮点类型的数字指定步长自增(浮点类型只能指定步长自增,incrbyfloat也是用整型)

set weight 66.6
INCRBYFLOAT weight 0.2	# 让weight自增0.2

image-20230910093759789

DECR、DECRBY、DECRBYFLOAT

自减,操作和上述自增一样

2.1.4SETNX和SETEX

setnx:已存在就不会改变键的值。NX是not exists的缩写。

setex:设定键的过期时间。EX是expire的缩写。

setnx key value:如果key不存在则创建一个String类型的键值对,如果key存在,则不执行。创建成功返回1,失败返回0。

setex key second:创建一个String类型的键值对,并设置过期时间,second为秒数

image-20230910094116046

利用这个机制可以自己定义一个分布式锁,因为我们在java中的sync / lock / unlock 的操作,本质只能在同一个jvm之中才能做到,分布式可以利用redis来完成类似锁的操作。

image-20230910094145171

2.1.5MSETNX

msetnx key value [key value ...]:批量添加多个String类型的键值对。

当且仅当要创建的所有key都不存在时才创建成功。只要有一个键已存在,则都创建失败。

image-20230910094410074

2.1.6SETRANGE和GETRANGE

这里和以前接触的很多截取不同的是 ——>前闭后闭

setrange key offset value:从指定位置替换值的内容,offset表示偏移量,如果为1表示从第二个字符开始。value为替换的内容。

image-20230910094754800

getrange key start end:获取key值指定范围的内容,start表示开始索引,end表示结束索引。0到-1表示获取全部。

image-20230910094845742

2.1.7STRLEN

strlen key:获取key值的长度

strlen str # 获取str值的长度

image-20230910094957476

2.1.8APPEND

append key value:在key值后追加内容value

append str hijklmn	# 在str值后追加内容hijklmn

image-20230910095055997

2.1.9GETSET

getset 过时了,但还能使用
getset key value:设置键值对时先获取原先的key值再设置新的key值,等价于set key get。

image-20230910095147441

2.1.10key的结构

Redis没有类似MySQL中的Table的概念,我们该如何区分不同类型的key呢?

例如,需要存储用户、商品信息到redis,有一个用户id是1,有一个商品id恰好也是1,此时如果使用id作为key,那就冲突了该怎么办?

我们可以通过给key添加前缀加以区分,不过这个前缀不是随便加的,有一定的规范:

Redis的key允许有多个单词形成层级结构,多个单词之间用’:'隔开,格式如下:

项目名:业务名:类型:id

这个格式并非固定,也可以根据自己的需求设计。这样我们就可以把不同类型的数据区分开了,从而避免了key的冲突问题。

例如我们的项目名称叫 heima,有user和product两种不同类型的数据,我们可以这样定义key:

  • user相关的key:heima:user:1
  • product相关的key:heima:product:1

如果Value是一个Java对象,例如一个User对象,则可以将对象序列化为JSON字符串后存储:

KEYVALUE
heima:user:1{“id”:1, “name”: “Jack”, “age”: 21}
heima:product:1{“id”:1, “name”: “小米11”, “price”: 4999}

并且,在Redis的桌面客户端中,还会以相同前缀作为层级结构,让数据看起来层次分明,关系清晰

image-20230910095605913

2.1.11应用场景

适用场景 :
抖音无限点赞一个视频或者商品,点一下加一次
是否喜欢的文章,在线统计有多少人喜欢

2.2List

image-20230910095712589

列表:

Redis的List类型是一个单key多value的集合,其value值是有序可重复的

Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。

特征与LinkedList类似:①有序 ②可重复 ③插入和删除速度快 ④查询速度一般

常用来存储一个有序数据,例如朋友圈点赞列表,评论列表等等。

  • 如果键不存在,创建新的链表;
  • 如果键已存在,新增内容,可重复;
  • 如果值全移除,对应的键也就消失了。

List类型的常用命令

2.2.1LPUSH和RPUSH

向列表头部或尾部插入元素。返回值为执行命令后列表的长度。当key不存在时则创建key。

LPUSH key element [element ...]:在列表key左边添加一个或多个元素,也就是在列表的头部添加元素。

RPUSH key element [element ...]:在列表key右边添加一个或多个元素,也就是在列表的尾部添加元素。

lpush list A B	# 创建一个列表,key为list
lpush list C D E	# 在列表左边(前面)追加C、D、E三个元素
rpush list X Y Z	# 在列表右边(后面)追加X、Y、Z三个元素

image-20230910100522292

image-20230910100531252

2.2.2LPUSHX和RPUSHX

仅当列表存在时入栈,返回值为执行命令后列表的长度。

LPUSHX key vlaue:将value值插入到列表Key的表头,当且仅当 key存在并且是一个列表。当key不存在,执行失败,返回0。

RPUSHX key value:将值 value插入到列表key的表尾,当且仅当 key存在并且是一个列表。当key不存在,执行失败,返回0。

image-20230910100952796

2.2.3LRANGE

没有RRANGE

LRANGE key start stop:返回列表 key中指定区间内的元素,区间以偏移量(索引) startstop 指定。

0表示第一个元素,1表示列表第二个元素;-1表示列表最后一个元素,-2表示列表倒数第二个元素,以此类推。

如果start的下标比列表最大的下标end(LLEN list减一)还大,那么Lrange返回一个空列表。

如果stop的下标比end的下标还要大,Redis将stop的值设置为end。0到-1表示列表的所有元素。

image-20230910101116588

image-20230910101127590

2.2.4LPOP和RPOP

弹出列表最左端或最右端的元素

LPOP key [count]:移除列表最左侧的元素并返回该元素,没有则返回nil,count为移除的个数。

RPOP key [count]:移除列表最右侧的元素并返回该元素,没有则返回nil,count为移除的个数。

image-20230910101249312

2.2.5BLPOP和BRPOP

B是blocking的缩写,表示阻塞的意思。

与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil。

BLPOP key [key ...] timeout:移除列表第一个元素并返回该元素,如果列表没有元素会阻塞队列直到等待超时或发现可弹出元素为止

BRPOP key [key ...] timeout:移除列表最后一个元素并返回该元素,如果列表没有元素会阻塞队列直到等待超时或发现可弹出元素为止

2.2.6RPOPLPUSH

RPOPLPUSH source destination:将列表source中的尾元素弹出插入到列表destination的头部,并返回该元素。

如果source不存在,返回nil。
如果source和destination相同,则列表中的表尾元素被移动到表头,并返回该元素,这种情况可以视为列表的旋转操作。

image-20230910101805980

Redis的列表经常被用作队列(queue),用于在不同程序之间有序地交换消息(message)。一个客户端通过 LPUSH命令将消息放入队列中,而另一个客户端通过 RPOP或者 BRPOP命令取出队列中等待时间最长的消息。

上面的队列方法是『不安全』的,因为在这个过程中,一个客户端可能在取出一个消息之后崩溃,而未处理完的消息也就因此丢失。

使用RPOPLPUSH命令(或者它的阻塞版本 BRPOPLPUSH )可以解决这个问题:因为它不仅返回一个消息,同时还将这个消息添加到另一个备份列表当中,如果一切正常的话,当一个客户端完成某个消息的处理之后,可以用 LREM 命令将这个消息从备份表删除。

最后,还可以添加一个客户端专门用于监视备份表,它自动地将超过一定处理时限的消息重新放入队列中去(负责处理该消息的客户端可能已经崩溃),这样就不会丢失任何消息了。

2.2.7LINDEX

LINDEX key index:通过索引获取列表元素。

下标(index)参数 startstop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。

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

如果 index 参数的值不在列表的区间范围内(out of range),返回 nil 。如果 key 不是列表类型,返回一个错误。

2.2.8LLEN

LLEN key:返回列表key的长度。

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

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

2.2.9LREM

remove的缩写,移除指定元素。

返回值:被移除元素的数量。不存在的 key 被视作空表(empty list),所以当 key 不存在时, LREM命令总是返回 0 。

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

count 的值可以是以下几种:

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

2.2.10LTRIM

对一个列表进行修剪(trim),让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。

LTRIM key start stop:让列表key只保留start-stop区间的元素。成功返回ok,若key不是列表类型返回错误。

下标(index)参数 startstop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

image-20230910102200139

2.2.11LSET

LSET key index value:将列表key下标为index的元素的值设置为value。操作成功返回ok。

当index参数超出范围,或对一个空列表(key不存在)进行LSET时,返回一个错误。关于更多的下标信息,参考LINDEX。

2.2.12LINSERT

LINSERT key BEFORE|AFTER element value:将值value插入到列表key中element元素之前或之后。

当element不存在列表key中时,不执行任何操作。当key不存在时,也不执行任何操作。若key不是列表类型,返回一个错误。

返回值:
如果命令执行成功,返回插入操作完成之后,列表的长度。
如果没有找到 element ,返回 -1 。
如果 key 不存在或为空列表,返回 0 。

image-20230910102348792

2.2.13应用场景

image-20230910102445799

2.3HASH

哈希表

hash类型,也叫做散列。其value是一个无序字典,类似于java中的HashMap结构。

K-V模式不变,但v又是一个键值对:Map<key,Map<key,value>>

String结构是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时很不方便:

image-20230910103729781

Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD,下面是两个哈希表:

image-20230910103749522

Hash类型的常用命令:

2.3.1HSET和HGET

HSET key field value [field value ...]:将hash表key中的域field的值设置为value,支持同时设置多个域-值对。

如果key不存在,一个新的hash表被创建并执行HSET操作。
如果域field不存在,表示新增field-value(域值对),如果域field已经存在哈希表key中,其旧值将被覆盖。

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

image-20230910104333940

HGET key field :根据给定域field返回对应的value值。当key不存在或者field不存在,返回nil

2.3.2HMSET和HMGET

在这之前HSET只能设置单个键值对,同时设置多个时必须使用HMSET。而现在HSET也允许接受多个键值对作参数了。根据Redis 4.0.0,HMSET被视为已弃用。请在新代码中使用HSET。

HMSET key field value [field value ...]:同时将多个field-value(域-值对)设置到哈希表key中。

此命令会覆盖哈希表中已存在的域,如果key不存在,一个空的哈希表被创建并执行HMSET操作。

返回值:执行成功返回ok;若key不是hash类型,返回一个错误。

HSET在Redis版本迭代后也支持同时设置多个值到哈希表中,与HMSET操作完全相同,HMSET今后可能被淘汰。

HMGET key field [field ...]:返回哈希表key中一个或多个给定的域值。

如果给定的域不存在于哈希表,那么返回一个 nil 值。key不存在时也返回一个nil值。key不是Hash类型时报错。

image-20230910104656135

2.3.3HGETALL

HGETALL key:返回哈希表key中所有的fieldvalue

在返回值里,紧跟着域名后的是域的值,所以返回值的长度是哈希表大小的两倍。

返回值:以列表形式返回哈希表的域和值,若key不存在,返回空列表。若key不是hash类型则报错。

若在Redis客户端这样显示的数据就是列表:
1)“AA”
2)“BB”
3)“CC”

image-20230910104753045

2.3.4HDEL

HDEL key field [field ...]:删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。

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

2.3.5HLEN

HLEN key:返回哈希表 key域的数量

返回值:返回哈希表中域的数量,当key不存在时返回0,若key不是hash类型则报错。

2.3.6HEXISTS

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

如果哈希表中存在给定域,返回 1
如果哈希表中不存在给定域,或 key 不存在,返回 0

2.3.7HKEYS和HVALS

HKEYS key:获取哈希表key中所有的field

返回值:返回哈希表中所有field的数组,若key不存在返回一个空数组。若key不是hash类型返回错误。

HVALS key:获取哈希表key中所有field对应的value值。

返回值:返回哈希表中所有field对应的value的数组,若key不存在返回一个空数组。若key不是hash类型返回错误。

2.3.8HINCR、HINCRBYFLOAT

HINCRBY key field increment:为哈希表 key 中的域 field 的值加上增量 increment只适用整型字符串

HINCRBYFLOAT key field increment:为哈希表 key 中的域 field 加上浮点数增量 increment只适用浮点型字符串

增量也可以为负数,相当于对给定域进行减法操作。

如果哈希表 key 不存在,那么会先创建一个哈希表,再创建域 field ,最后再执行HINCRBY HINCRBYFLOAT操作。

如果域 field 不存在,那么在执行命令前,域的值被初始化为 0 ,然后后执行HINCRBY HINCRBYFLOAT操作。

对一个储存非整型字符串的域 field 执行 HINCRBY 命令将造成一个错误。

对一个储存非数值型字符串的域 field 执行HINCRBYFLOAT 命令将造成一个错误。

本操作的值被限制在 64 位(bit)有符号数字表示之内。

2.3.9HSETNX

HSETNX key field value:向哈希表key中添加field-value,当且仅当域field不存在。

若field已存在,则该操作无效;若key不存在,则创建该哈希表并执行HSETNX操作。

返回值:添加成功,返回1;如果给定域已经存在返回 0 。

2.3.10 应用场景

一些中小厂的购物车的使用:

新增商品 → hset shopcar:uid1024 334488 1

新增商品 → hset shopcar:uid1024 334477 1

增加商品数量 → hincrby shopcar:uid1024 334477 1

商品总数 → hlen shopcar:uid1024

全部选择 → hgetall shopcar:uid1024

2.4Set

最主要的是集合运算

集合

Redis的Set类型是一个和List一样的单key多value的集合,与List不同的是Set的value是无序且不可重复的

Redis的set相当于Java语言里面的HashSet,它内部键值对是无序的、唯一的。它的内部实现相当于一个特殊的字典,字典中所有的value都是一个值NULL,可以看做是一个value为null的HashMap。

具备与HashSet类似的特征:

  • 无序
  • 元素不可重复
  • 查找快
  • 支持交集、并集、差集等功能

应用场景
微信抽奖小程序。(SRANDMEMBER)
微信朋友圈共友点赞。(SINTER)
QQ推荐可能认识的人。(SDIFF)

image-20230910105525034

image-20230910105548749

Set类型的常用命令:

2.4.1SADD

SADD key member [member ...]:将一个或多个 member 元素加入到set集合 key 当中,已经存在于集合的 member 元素将被忽略。

假如 key 不存在,则创建一个只包含 member 元素作成员的集合。

key 不是Set集合类型时,返回一个错误。

返回值:被添加到集合中的新元素的数量,不包括被忽略的元素。

2.4.2SMEMBERS

SMEMBERS key:返回集合key中所有的成员。

若key不存在,返回空数组;若key不是Set集合,返回错误。

2.4.3 SISMEMBER

S表示Set集合,ISMEMBER表示is member?

SISMEMBER key member:判断 member 元素是否是集合 key 的成员。

如果 member 元素是集合的成员,返回 1

如果 member 元素不是集合的成员,或 key 不存在,返回 0

image-20230910105950509

2.4.4SCARD

SCARD key:返回集合key中成员的个数。当key不存在时,返回0。若key不是Set集合类型,返回错误。

2.4.5SREM

SREM key member [member ...]:移除集合key中的一个或多个member元素并返回移除的个数,不存在的member元素会被忽略。

2.4.6SRANDMEMBER

SRANDMEMBER key [count]:随机返回集合中一个[或多个]元素。仅仅返回随机元素,而不对集合进行任何改动。

SRANDMEMBER命令可选的 count 参数:

  • 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。
  • 如果 count 大于等于集合基数,那么返回整个集合。
  • 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。

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

image-20230910110235538

2.4.7SPOP

SPOP key [count] :移除并返回集合中的一个[或多个]随机元素。

如果只想获取一个随机元素,但不想该元素从集合中被移除的话,可以使用 SRANDMEMBER命令。

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

2.4.8 SMOVE

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

SMOVE是原子性操作。

如果 source 集合不存在或不包含指定的 member 元素,则 SMOVE 命令不执行任何操作,仅返回 0 。

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

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

返回值:

如果 member 元素被成功移除,返回 1 。

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

127.0.0.1:6379> smembers course					# 集合course有三个成员
1) "Go"
2) "Python"
3) "Java"
127.0.0.1:6379> smembers subject				# 集合subject有四个成员
1) "Chinese"
2) "Physics"
3) "English"
4) "Math"
127.0.0.1:6379> SMOVE subject course Physics	# 将集合subject的成员Physics移动到集合course中
(integer) 1
127.0.0.1:6379> SMEMBERS course					# 集合course中新增成员Physics
1) "Physics"
2) "Go"
3) "Python"
4) "Java"
127.0.0.1:6379> SMEMBERS subject				# 集合subject中少了一个成员
1) "Chinese"
2) "English"
3) "Math"
127.0.0.1:6379> SADD subject Go					# 新增成员Go到集合subject
(integer) 1
127.0.0.1:6379> SMOVE subject course Go			# 移动成员Go从subject到course(Go在两个集合中都存在)
(integer) 1
127.0.0.1:6379> SMEMBERS subject				# 自身减少了一个成员
1) "Chinese"
2) "English"
3) "Math"
127.0.0.1:6379> SMEMBERS course					# course本身就已有Go成员,所以不执行任何操作(也可以理解为覆盖了)
1) "Physics"
2) "Go"
3) "Python"
4) "Java"

2.4.9集合运算

SDIFF

SDIFF key key2 ...:返回给定集合的差集。

sdiff A B:返回属于集合A但不属于集合B的元素
sdiff B A:返回属于集合B但不属于集合A的元素

image-20230910110648079

SUNION

SUNION key [key ...]:返回给定集合的并集。

比如sunion A B表示返回集合A和集合B的所有元素,公共的只取一份。

image-20230910110737666

SINTER

SINTER key [key ...]:返回给定集合的交集。

比如sinter A B表示即返回集合A和集合B共有的元素。

image-20230910110820031

SINTERCARD numkeys key [key ...] [LIMIT limit] :返回给定集合交集的个数。

numkeys为key的个数。

LIMIT为限制返回的个数的最大值,比如交集个数有10个,但是LIMIT为5,则返回5。

image-20230910111027071

2.4.10应用场景

1.微信抽奖小程序

image-20230910111104780

2.查看微信点赞共同好友

image-20230910111125984

3.QQ内推可能认识的人

image-20230910111145135

2.5SortedSet

有序集合

SortedSet也叫ZSet。在Set的基础上,每个member前面加个score属性。

Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。

SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加 hash表。

score的值是一个整型数值或者浮点数值 的数,是可重复的。

SortedSet具备下列特性:

  • 可排序
  • 元素不重复
  • 查询速度快

因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能,比如商品销售排行榜

image-20230910212955877

Zset类型的常用命令:

2.5.1ZADD

ZADD key score member [[score member] [score member] ...]:将一个或多个元素及其score值添加到有序集合key中。

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

score是一个用于排序的属性,它的值是整数值或双精度浮点数,score写在member的前面。

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

当然还可以加其他参数比如NXXXINCR等等

127.0.0.1:6379> ZADD userZset 10 Alice 20 Bob 30 Cindy 40 Davie	# 添加四个成员
(integer) 4		# 返回添加成功的个数

2.5.2ZCARD

ZCARD key :返回有序集 key 中成员的个数。当key不存在时返回0,若key不是有序集类型,返回错误。

127.0.0.1:6379> ZCARD userZset		# 获取有序集userZset中成员的个数
(integer) 4		# 四个

2.5.3ZCOUNT

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

默认情况下,区间的取值使用闭区间(小于等于或大于等于),也可以通过给参数前增加 ( 符号将其改变为开区间。
比如 (1 5 表示 1<score<=5,(1 (5 表示 1<score<5。

2.5.4ZSCORE

ZSOCRE key member:返回有序集 key 中指定成员 memberscore 值。

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

返回值:member 成员的 score 值,以字符串形式表示。

2.5.5ZRANGE和ZREVRANGE

ZRANGE key start stop [WITHSCORES]:返回有序集合key中指定区间的成员。从小到大排序

其中成员的位置是按score值从小到大排序,具有相同score的车成员按字典序来排列。区间(下标参数)这里不再赘述。

WITHSCORES 选项,表示让成员和它的 score 值一并返回,返回列表以 member1,score1, ..., memberN,scoreN 的格式表示。

可能会返回一些更复杂的数据类型,比如数组、元组等。

如果需要按score值从大到小排序,可以适用ZREVRANGE命令。

ZREVRANGE key start stop [WITHSCORES]:返回有序集合key中指定区间的成员。从大到小排序

成员的位置是按照score值从大到小排序,其余都和ZRANGE一样。

2.5.6ZRANGEBYSCORE和ZREVRANGEBYSCORE

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]:返回有序集 key 中所有 score 值介于 minmax 之间(包括等于 minmax )的成员。按score值从小到大排序

默认情况下,区间的取值使用闭区间(小于等于或大于等于),也可以通过给参数前增加 ( 符号来使用可选的开区间(小于或大于)。

比如 (1 5 表示 1<score<=5,(1 (5 表示 1<score<5。

LIMIT 参数限制返回结果的区间(就像SQL中的 SELECT ... LIMIT offset, count ),offset为下标偏移量,count为个数。

WITHSCORES 表示将有序集成员及其 score 值一起返回。

ZREVRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]:返回有序集 key 中所有 score 值介于minmax 之间(包括等于 minmax )的成员。按score值从大到小排序,其余参考ZRANGEBYSCORE。

2.5.7ZRANK和ZREVRANK

ZRANK key member:返回有序集 key 中指定成员 member 的排名。从小到大

排名按 score 值递增(从小到大)顺序排列。排名以 0 为底,也就是说score 值最小的成员排名为 0

使用 ZREVRANK 命令可以获得成员按 score 值递减(从大到小)排列的排名。

ZREVRANK key member:返回有序集 key 中指定成员 member 的排名。从大到小

2.5.8ZREM

ZREM key member [member ...]:移除有序集key中一个或多个成员,不存在的成员将被忽略。

当key不存在时返回0;当key存在但不是有序集时返回一个错误。

移除成功返回移除成员的数量。

127.0.0.1:6379> ZADD testZset 10 A 20 B 30 C 40 D 50 E
(integer) 5
127.0.0.1:6379> ZREM testZset C D E		# 移除三个成员
(integer) 3		# 移除成功返回3

2.5.9ZINCRBY

ZINCRBY key increment member:为有序集 key 的成员 memberscore 值加上增量 increment

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

返回值:返回member 成员的新 score 值,以字符串形式表示。
key 不是有序集类型时,返回一个错误。

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

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

2.5.10ZPOPMAX和ZPOPMIN

ZPOPMAX key [count]:删除并返回有序集keyscore值最大的一个[或多个]成员。

ZPOPMIN key [count]:删除并返回有序集keyscore值最小的一个[或多个]成员

2.5.11ZMPOP

ZMPOP numkeys key [key ...] <MIN | MAX> [COUNT count] :从所提供的键名列表中的第一个非空排序集中弹出一个[或多个]元素,这些元素是成员分数对。

这个指令就是ZPOPMAX和ZPOPMIN的升级版,可以对多个有序集合进行操作。

2.5.12集合运算

ZDIFF:求差集
ZINTER:求交集
ZUNION:求并集

2.5.13应用场景

根据商品销售对商品进行排序,这里应该是倒序

image-20230910214113232

2.6Bitmap

位图

用String类型作为底层数据结构实现的一种统计二值状态的数据类型。

位图本质是数组,该数组由多个二进制位组成,其值只能是1或0,默认0,每个二进制位都对应一个偏移量(我们称之为一个索引)。

Bitmap支持的最大位数是2^32位,它可以极大的节约存储空间,使用512M内存就可以存储多达42.9亿的字节信息。

(512102410248=2921021023=2^32)

一个字节占有8位,若在一个bitmap类型的key中,偏移量(索引)为8的位置存入1,前面7位会默认设置为0,那么该key占用两个字节,因为偏移量为8的那一位属于第二个字节了。
所以bitmap的扩容机制是根据位来看,如果使用 STRLEN key 获取的不是字符数,而是字节数量

应用 :由于offset值得范围是[0,2^32-1],这个数非常大,可以将用户id和偏移量形成映射关系来存储很多二值数据:
通常先将用户存储到哈希表中,通过field值来标识每一位用户,然后再将field值和偏移量形成映射关系,比如

HSET user 1 uid1001 2 uid1002 :1代表uid1001,2代表uid1002
SETBIT sign:Monday 1 1 偏移量1的位置值为1,偏移量1对应用户uid1001(1表示已签到,0表示未签到)

SETBIT sign:Monday 2 1 偏移量2的位置值为1,偏移量2对应用户uid1002

SETBIT sign:Monday n 1
再通过BITCOUNT sign:Monday就很容易获取Monday签到的用户数量了。

image-20230910214303859

Bitmap结构的常用命令:

2.6.1SETBIT

SETBIT key offset value:设置key的value(字符串)在offset处的bit值。

offset:偏移量,从0开始,最大值2^32-1

返回值:在offset处原来的bit值。

2.6.2GETBIT

GETBIT key offset:返回key对应的value在offset处的bit值。

当offset超出了字符串长度的时候,超出的部分就被假定为由0比特填充的连续空间。
当key不存在的时候,它就认为是一个空字符串,所以offset总是超出范围,然后value也被认为是由0比特填充的连续空间。

127.0.0.1:6379> GETBIT mybit 2		# 获取offset为2的值
(integer) 1
127.0.0.1:6379> GETBIT mybit 100	# 获取offset为100的值,100已经超出了该字符串的长度,默认超出的比特位都是0
(integer) 0
127.0.0.1:6379> STRLEN mybit		# 获取mybit的长度(占用字节数),因为只存储5位,不够一个字节,所以占用一个字节
(integer) 1
127.0.0.1:6379> SETBIT mybit 5 1
(integer) 0
127.0.0.1:6379> SETBIT mybit 6 0
(integer) 0
127.0.0.1:6379> SETBIT mybit 7 1
(integer) 0
127.0.0.1:6379> SETBIT mybit 8 1	# 偏移量8,属于第二个字节了,所以mybit的长度为2
(integer) 0
127.0.0.1:6379> STRLEN mybit
(integer) 2

2.6.3BITCOUNT

BITCOUNT key [start end [byte|bit]]:统计value中比特位为1的个数。

可以指定特定的比特位区间或字节区间,只统计该区间上比特位为1的个数。
byte表示一个字节为一个偏移量,bit表示一个位为一个偏移量。

127.0.0.1:6379> BITCOUNT mybit	# 统计整个字符串value中比特位为1的个数
(integer) 6
127.0.0.1:6379> BITCOUNT mybit 3 6 bit	# 统计比特位区间[3,6]中比特位为1的个数
(integer) 1
127.0.0.1:6379> BITCOUNT mybit 1 -1 byte	# 统计第二个字节及以后的字节中比特位为1的个数
(integer) 1

2.6.4BITOP

BITOP operation destkey key [key ...]:对一个或多个保存二进制位的字符串key进行位运算,并将结果保存到destkey中。

operation有四种操作:AND、OR、NOT、XOR

  • BITOP AND destkey srckey1 srckey2 srckey3 ... srckeyN :对一个或多个 key 求按位与(同一列都为1则为1)

  • BITOP OR destkey srckey1 srckey2 srckey3 ... srckeyN:对一个或多个 key 求按位或(同一列有一个1即为1)

  • BITOP XOR destkey srckey1 srckey2 srckey3 ... srckeyN:对一个或多个 key 求按位异或(不同则为1)

  • BITOP NOT destkey srckey:对给定 key 求按位取反(1变0,0变1)

    返回值:保存到destkey的字符串的长度(多少字节)

# 设置一个bitmap类型的bitmap1,存储1 0 1 0
127.0.0.1:6379> SETBIT bitmap1 0 1
(integer) 0
127.0.0.1:6379> SETBIT bitmap1 1 0
(integer) 0
127.0.0.1:6379> SETBIT bitmap1 2 1
(integer) 0
127.0.0.1:6379> SETBIT bitmap1 3 0
(integer) 0
# 设置一个bitmap类型的bitmap2,存储1 0 1 1
127.0.0.1:6379> SETBIT bitmap2 0 1
(integer) 0
127.0.0.1:6379> SETBIT bitmap2 1 0
(integer) 0
127.0.0.1:6379> SETBIT bitmap2 2 1
(integer) 0
127.0.0.1:6379> SETBIT bitmap2 3 1
(integer) 0

# 将这两个key做按位与运算,并将结果存到bitmap12中
127.0.0.1:6379> BITOP and bitmap12 bitmap1 bitmap2
(integer) 1		# 返回bitmap12的长度,1个字节
# 获取bitmap12的值
127.0.0.1:6379> GETBIT bitmap12 0	
(integer) 1
127.0.0.1:6379> GETBIT bitmap12 1
(integer) 0
127.0.0.1:6379> GETBIT bitmap12 2
(integer) 1
127.0.0.1:6379> GETBIT bitmap12 3
(integer) 0
可以看到得出的数是1 0 1 0

# 将bitmap1做按位取反运算
127.0.0.1:6379> BITOP not destkey1 bitmap1
(integer) 1
# 获取destkey1的值
127.0.0.1:6379> GETBIT destkey1 0
(integer) 0
127.0.0.1:6379> GETBIT destkey1 1
(integer) 1
127.0.0.1:6379> GETBIT destkey1 2
(integer) 0
127.0.0.1:6379> GETBIT destkey1 3
(integer) 1
可以看到取反后的数为0 1 0 1

2.6.5应用场景

1.统计一年365天,全年天天登录所占字节

image-20230910214800938

2.按照年
这里应该是440MB

image-20230910214815776

2.7HyperLogLog

基数统计

HyperLogLog是一种概率数据结构,用于计数唯一的事物(技术上这是指估计一个集合的基数)。
(基数就是一个数据集中去除重复数据后总的个数)

HyperLogLog的数据类型还是String。在Redis中的HyperLogLog,虽然技术上是不同的数据结构,但被编码为Redis字符串。

在Redis里面每个HyperLogLog键只需要花费12kb内存就可以统计接近2^64个不同元素的基数。

HyperLogLog只会根据输入的元素来计算基数,不会存储输入的元素本身,所以HyperLogLog不能像集合那样返回输入的元素。

HyperLogLog结构的常用命令:

2.7.1PFADD

PFADD key element [element ...]:将元素element添加到HyperLogLog结构的key中。

如果 HyperLogLog 的内部被修改了,那么返回 1,否则返回 0 。

如果在调用该命令时仅提供变量名而不指定元素也是可以的,如果这个变量名存在,则不会有任何操作。如果不存在,则会创建一个数据结构(返回1)。

127.0.0.1:6379> PFADD hll a b c c d d f f g g	# 添加10个元素
(integer) 1		# 添加了10个元素,返回1
127.0.0.1:6379> PFADD hll a b c c d d f f g g	# 重复添加,HLL内部没有改变,返回0
(integer) 0

2.7.2PFCOUNT

PFCOUNT key [key ...]:返回给定HyperLogLog结构的key的基数。

当参数为一个key时,返回存储在HyperLogLog结构体的该key的近似基数,如果该变量不存在,则返回0。

当参数为多个key时,返回这些HyperLogLog并集的近似基数,这个值是将所给定的所有key的HyperLoglog结构合并到一个临时的HyperLogLog结构中计算而得到的。

127.0.0.1:6379> PFADD hll a b c c d d f f g g
(integer) 0	
127.0.0.1:6379> PFCOUNT hll		# 统计hll的基数(去重统计)
(integer) 6

2.7.3PFMERGE

PFMERGE destkey [sourcekey [sourcekey ...]]:将多个HyperLogLog合并成一个HyperLogLog。

destkey是合并后的HyperLogLog结构。

这个命令可以用PFCOUNT命令实现。

127.0.0.1:6379> PFADD hll1 a a b b c c d e f	# 创建一个HyperLogLog结构的hll1
(integer) 1
127.0.0.1:6379> PFADD hll2 d e f g g h h i i	# 创建一个HyperLogLog结构的hll2
(integer) 1
127.0.0.1:6379> PFMERGE hll3 hll1 hll2			# 合并这两个HyperLogLog结构的key
OK
127.0.0.1:6379> PFCOUNT hll3					# 统计合并后HyperLogLog结构的hll3的基数
(integer) 9
127.0.0.1:6379> PFCOUNT hll1 hll2				# 直接统计hll1和hll2
(integer) 9

2.7.4应用场景

统计天猫亿级UV访问数

2.8Geospatial

地理空间

Redis地理空间索引可以存储坐标并搜索它们。此数据结构用于在给定半径或包围框内查找附近点。

Geopatial的数据类型是Zset,相当于由之前的score变成了longitudelatitude,可以使用Zset的命令对其进行操作。

Geospatial结构的常用命令:

2.8.1GEOADD

GEOADD key [NX | XX] [CH] longitude latitude member [longitude latitude member ...]

将指定的地理空间项(经度、纬度、名称)添加到地理空间结构的key中。

数据以有序集的形式存储到键中,这样就可以使用GEOSEARCH命令查询项。

规定如下:

  • 有效的经度从-180度到180度。
  • 有效的纬度从-85.05112878度到85.05112878度。

当坐标位置超出上述指定范围时,该命令将会返回一个错误。

GEOADD city 116.403963 39.915119 "天安门" 116.403414 39.924091 "故宫" 116.024067 40.362639 "长城"

2.8.2GEOPOS

GEOPOS key member [member ...]:从给定的key里返回所有指定member的位置(经度和纬度),不存在的member返回nil。

GEOPOS 命令返回一个数组, 数组中的每个项都由两个元素组成: 第一个元素为给定位置元素的经度, 而第二个元素则为给定位置元素的纬度。给定的位置元素不存在时, 对应的数组项为空值。

127.0.0.1:6379> GEOPOS city 天安门 故宫 长城
116.40396326780319214
39.91511970338637383
116.40341609716415405
39.92409008156928252
116.02406591176986694
40.36263993239462167

2.8.3GEOHASH

GEOHASH key member [member ...]:获取一个或多个member的geohash值。

通常使用表示位置的元素使用不同的技术,使用Geohash位置52点整数编码。
由于编码和解码过程中所使用的初始最小和最大坐标不同,编码的编码也不同于标准。此命令返回一个标准的Geohash。

127.0.0.1:6379> GEOHASH city 天安门 故宫 长城
wx4g0f6f2v0
wx4g0gfqsj0
wx4t85y1kt0

2.8.4GEODIST

GEODIST key member1 member2 [M | KM | FT | MI]:返回两个给定member之间的距离。

如果两个位置之间的其中一个不存在, 那么命令返回空值。

  • m 表示单位为米。

  • km 表示单位为千米。

  • mi 表示单位为英里。

  • ft 表示单位为英尺。

    如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用M作为单位。

127.0.0.1:6379> GEODIST city 天安门 长城
59338.9814		# 天安门距离长城59338.9814米
127.0.0.1:6379> GEODIST city 天安门 长城 km
59.3390			# 天安门距离长城59.3390千米

2.8.5GEORADIUS

GEORADIUS key longitude latitude radius <M | KM | FT | MI> [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC | DESC] [STORE key] [STOREDIST key]

以给定的经纬度为中心, 返回key包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

radius:半径

WITHDIST:在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。

WITHCOORD: 将位置元素的经度和维度也一并返回。

WITHHASH:将geohash值一并返回。

COUNT :限定返回的记录数。

ASC:由近到远返回(升序)

DESC:由远到近返回(降序)

假设当前位置北京王府井(116.418017 39.914402)
# 由近到远排序
127.0.0.1:6379> GEORADIUS city 116.418017 39.914402 10 km withdist withcoord withhash count 10
天安门					  # member
1.2016					# 天安门距离北京王府井1.2km
4069885555089531		# geohash值
116.40396326780319214	# 经度值
39.91511970338637383	# 纬度值
故宫
1.6470					# 故宫距离北京王府井1.6km
4069885568908290
116.40341609716415405
39.92409008156928252
# 由远到近排序
127.0.0.1:6379> GEORADIUS city 116.418017 39.914402 10 km withdist withcoord withhash count 10 desc
故宫
1.6470
4069885568908290
116.40341609716415405
39.92409008156928252
天安门
1.2016
4069885555089531
116.40396326780319214
39.91511970338637383
# 将半径改为70km,这样长城也在范围内
127.0.0.1:6379> GEORADIUS city 116.418017 39.914402 70 km withdist withcoord withhash count 10 desc
长城
60.0642					# 长城距离北京王府井60km
4069895262981475
116.02406591176986694
40.36263993239462167
故宫
1.6470
4069885568908290
116.40341609716415405
39.92409008156928252
天安门
1.2016
4069885555089531
116.40396326780319214
39.91511970338637383

2.8.6GEORADIUSBYMEMBER

GEORADIUSBYMEMBER key member radius <M | KM | FT | MI> [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC | DESC] [STORE key] [STOREDIST key]

以给定的位置元素为中心点,找出位于指定范围内的元素。其他和GEORADIUS命令一样

# 获取距离天安10km范围内的位置元素
127.0.0.1:6379> GEORADIUSBYMEMBER city 天安门 10 km withdist withcoord withhash count 10 desc
故宫
0.9988
4069885568908290
116.40341609716415405
39.92409008156928252
天安门
0.0000
4069885555089531
116.40396326780319214
39.91511970338637383

2.9Stream

redis5 之前实现消息队列痛点
可以使用list来实现点对点的模式

image-20230910220757763

pub/sub实现多对多

image-20230910221202747


相当于Redis版的MQ消息中间件 + 阻塞队列

Redis流是一种数据结构(Stream类型),它的作用类似于只能追加的日志。您可以使用流来实时记录和同时聚合事件

Redis流用例示例包括:

  • 事件来源(例如,跟踪用户操作、点击等)
  • 传感器监测(例如,来自现场设备的读数)
  • 通知(例如,在单独的流中存储每个用户通知的记录)

Redis为每个流消息生成一个唯一的ID,可以使用这些id检索它们关联的消息,或者读取和处理流中的所有后续消息。

四种和ID有关的特殊符号:
-+:当前流中最小ID和最大ID
$:表示大于当前流中最大的id,用于新添加的消息
>:用于XREANGROUP命令,表示迄今没有发送给组中使用者的信息,会更新消费者组的最后ID
*:用于XADD命令中,表示让系统自动生成ID

Stream流就是Redis版的MQ消息中间件+阻塞队列,它能实现消息队列,它支持消息的持久化、支持自动生成全局唯一ID、支持ack确认消息的模式、支持消费组模式等,让消息队列更加的稳定和可靠。

image-20230910221730513

Message Content:消息内容

Consumer group:消费组,通过XGROUP CREATE 命令创建,同一个消费组可以有多个消费者

Last_delivered_id:游标,每个消费组会有个游标 last_delivered_id,任意一消费者读取了消息都会使游标 last_delivered_id 往前移动。

Consumer:消费者,消费组中的消费者

Pending_ids:消费者会有一个状态变量,用于记录被当前消费已读取但未ack的消息Id,如果客户端没有ack,这个变量里面的消息ID会越来越多,一旦某个消息被ack它就开始减少。这个pending_ids变量在Redis官方被称之为 PEL(Pending Entries List),记录了当前已经被客户端读取的消息,但是还没有 ack (Acknowledge character:确认字符),它用来确保客户端至少消费了消息一次,而不会在网络传输的中途丢失了没处理

Stream类型得常用命令:

2.9.1XADD

XADD key [NOMKSTREAM] [<MAXLEN | MINID> [= | ~] threshold [LIMIT count]] <\* | id> field value [field value ...]

将消息追加到指定流key的末尾,添加的消息ID要比上个消息的ID大。如果key不存在,将自动创建流key然后执行XADD操作。

ID用于标识给定消息,如果指定的ID参数是字符*XADD命令会自动生成一个唯一的ID。ID是由时间戳-序列号两部分组成,当自动生成ID时,第一部分是生成ID的Redis实例的毫秒格式的Unix时间。 第二部分是一个序列号,用来区分同一毫秒内生成的ID的。序列号是64位长度(18446744073709551615),理论上在同一毫秒内生成的数据量无法到达这个级别,因此不用担心序列号会不够用。该命令返回添加的消息的ID。如果ID参数传的是*,那么ID是自动生成的, 否则,命令仅返回用户在插入期间指定的相同的ID。

通常使用命令XADD ID filed value [field value ...],其他的花里胡哨的参数了解即可。

127.0.0.1:6379> XADD mystream * name tom age 20	# 添加一条消息到mystream队列末尾,自动生成id
"1681002319038-0"	# 返回生成消息的id
127.0.0.1:6379> XADD mystream 1681002319038-0 name tom age 20	# 如果添加消息的id不比上一消息id大,则报错
(error) ERR The ID specified in XADD is equal or smaller than the target stream top item
127.0.0.1:6379> XADD mystream 1681002319038-1 name tom age 20	# 比上一消息id大,添加成功,返回添加消息的id
"1681002319038-1"
127.0.0.1:6379> 

2.9.2XRANGE

XRANGE key start end [COUNT count]:返回给定id范围内流key的消息。

id范围由[start,end]指定。特殊ID:- 表示流中最小的消息id,+表示流中最大的消息id。

返回的消息由id从小到大排序。

127.0.0.1:6379> XADD mystream * name Alice age 20
"1681003546319-0"
127.0.0.1:6379> XADD mystream * name Bob age 21
"1681003556153-0"
127.0.0.1:6379> XADD mystream * name Cindy age 22
"1681003570177-0"
127.0.0.1:6379> XADD mystream * name Davie age 23
"1681003595504-0"
127.0.0.1:6379> XRANGE mystream - +		# - + 表示返回流mystream中所有的消息,且根据id从小到大排序
1) 1) "1681003546319-0"
   2) 1) "name"
      2) "Alice"
      3) "age"
      4) "20"
2) 1) "1681003556153-0"
   2) 1) "name"
      2) "Bob"
      3) "age"
      4) "21"
3) 1) "1681003570177-0"
   2) 1) "name"
      2) "Cindy"
      3) "age"
      4) "22"
4) 1) "1681003595504-0"
   2) 1) "name"
      2) "Davie"
      3) "age"
      4) "23"
127.0.0.1:6379> XRANGE mystream - + count 2		# 限制返回两个
1) 1) "1681003546319-0"
   2) 1) "name"
      2) "Alice"
      3) "age"
      4) "20"
2) 1) "1681003556153-0"
   2) 1) "name"
      2) "Bob"
      3) "age"
      4) "21"

2.9.3 XREVRANGE

XREVRANGE key end start [COUNT count]:返回给定id范围内流key的消息。

XREVRANGE中,要先指定结束ID,再指定开始ID,返回消息的顺序是根据id从大到小排序。其余和XRANGE一样。

127.0.0.1:6379> XREVRANGE mystream + -
1) 1) "1681003595504-0"
   2) 1) "name"
      2) "Davie"
      3) "age"
      4) "23"
2) 1) "1681003570177-0"
   2) 1) "name"
      2) "Cindy"
      3) "age"
      4) "22"
3) 1) "1681003556153-0"
   2) 1) "name"
      2) "Bob"
      3) "age"
      4) "21"
4) 1) "1681003546319-0"
   2) 1) "name"
      2) "Alice"
      3) "age"
      4) "20"
127.0.0.1:6379> XREVRANGE mystream + - count 2
1) 1) "1681003595504-0"
   2) 1) "name"
      2) "Davie"
      3) "age"
      4) "23"
2) 1) "1681003570177-0"
   2) 1) "name"
      2) "Cindy"
      3) "age"
      4) "22"

2.9.4XDEL

XDEL key id [id ...]:从流key中删除指定id(消息)。

127.0.0.1:6379> XDEL mystream 1681003595504-0 1681003556153-0	# 删除Bob和Davie对应的id
(integer) 2		# 成功删除两个
127.0.0.1:6379> XRANGE mystream - +
1) 1) "1681003546319-0"
   2) 1) "name"
      2) "Alice"
      3) "age"
      4) "20"
2) 1) "1681003570177-0"
   2) 1) "name"
      2) "Cindy"
      3) "age"
      4) "22"

2.9.5 XLEN

XLEN mystream:返回流key中消息的条数。

127.0.0.1:6379> XLEN mystream	# 流mystream中有两条消息
(integer) 2

2.9.6XTRIM

XTRIM key <MAXLEN | MINID> [= | ~] threshold [LIMIT count]:将流消息裁剪为指定数量的消息。

MAXLEN:表示允许最大的消息长度(个数),超过此数量会优先删除id较小的消息。

MINID:表示允许最小的id,比此id还小的消息会被删除。

返回值:删除消息的数量。

# 创建五条消息存入流mystream中
127.0.0.1:6379> XADD mystream 1681006080120-0 name Alice age 18
"1681006080120-0"
127.0.0.1:6379> XADD mystream 1681006080120-1 name Bob age 19
"1681006080120-1"
127.0.0.1:6379> XADD mystream 1681006080120-2 name Cindy age 20
"1681006080120-2"
127.0.0.1:6379> XADD mystream 1681006080120-3 name Davie age 21
"1681006080120-3"
127.0.0.1:6379> XADD mystream 1681006080120-4 name Eric age 22
"1681006080120-4"
127.0.0.1:6379> XTRIM mystream maxlen 3		# 获取最近的3条消息,id较小的被删除(id是递增的)
(integer) 2
127.0.0.1:6379> XRANGE mystream - +
1) 1) "1681006080120-2"
   2) 1) "name"
      2) "Cindy"
      3) "age"
      4) "20"
2) 1) "1681006080120-3"
   2) 1) "name"
      2) "Davie"
      3) "age"
      4) "21"
3) 1) "1681006080120-4"
   2) 1) "name"
      2) "Eric"
      3) "age"
      4) "22"	
127.0.0.1:6379> XTRIM mystream minid 1681006080120-3	# 获取id不小于1681006080120-3的消息
(integer) 1
127.0.0.1:6379> XRANGE mystream - +
1) 1) "1681006080120-3"
   2) 1) "name"
      2) "Davie"
      3) "age"
      4) "21"
2) 1) "1681006080120-4"
   2) 1) "name"
      2) "Eric"
      3) "age"
      4) "22"

2.9.7XREAD

XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]

从一个或者多个流中读取数据,仅返回id大于对应流中最大id的消息(也就是新添加的消息)。

count:最多读取多少条

block:是否以阻塞的方式读取,如果开启且milliseconds设为0,表示永远阻塞直到读取到消息。

id:表示读取ID大于指定id的消息。

特殊ID:符号$。表示以当前Stream已经存储的最大的ID作为最后一个ID,当前Stream中不存在大于当前最大ID的消息,因此此时返回nil。一般用于阻塞队列获取新消息。

# 数据准备,创建两个流stream1和stream2
127.0.0.1:6379> XADD stream1 1681006080120-0 name Alice
"1681006080120-0"
127.0.0.1:6379> XADD stream1 1681006080120-1 name Bob
"1681006080120-1"
127.0.0.1:6379> XADD stream1 1681006080120-2 name Cindy
"1681006080120-2"
127.0.0.1:6379> XADD stream1 1681006080120-3 name Davie
"1681006080120-3"
127.0.0.1:6379> XADD stream1 1681006080120-4 name Eric
"1681006080120-4"
127.0.0.1:6379> XADD stream2 1681008731850-0 1 one
"1681008731850-0"
127.0.0.1:6379> XADD stream2 1681008731850-1 2 two
"1681008731850-1"
127.0.0.1:6379> XADD stream2 1681008731850-2 3 three
"1681008731850-2"
127.0.0.1:6379> XADD stream2 1681008731850-3 4 four
"1681008731850-3"
127.0.0.1:6379> XADD stream2 1681008731850-4 5 five
"1681008731850-4"
127.0.0.1:6379> XADD stream2 1681008731850-5 6 six
"1681008731850-5"

127.0.0.1:6379> XREAD count 3 streams stream1 0-0	# count 3表示只获取3个,0-0表示从最小的ID开始获取Stream中的消息
1) 1) "stream1"
   2) 1) 1) "1681006080120-0"
         2) 1) "name"
            2) "Alice"
      2) 1) "1681006080120-1"
         2) 1) "name"
            2) "Bob"
      3) 1) "1681006080120-2"
         2) 1) "name"
            2) "Cindy"
            
127.0.0.1:6379> XREAD count 3 streams stream1 0		# 使用0也可以表示从最小的ID开始获取Stream中的消息,000也可以
1) 1) "stream1"
   2) 1) 1) "1681006080120-0"
         2) 1) "name"
            2) "Alice"
      2) 1) "1681006080120-1"
         2) 1) "name"
            2) "Bob"
      3) 1) "1681006080120-2"
         2) 1) "name"
            2) "Cindy"
            
127.0.0.1:6379> XREAD count 3 streams stream1 $		# $表示读取大于当前流中最大的id的消息
(nil)


# 读取stream1中id大于1681006080120-2的三条消息,读取stream2中id大于1681008731850-3的三条消息
127.0.0.1:6379> XREAD count 3 block 0 streams stream1 stream2 1681006080120-2 1681008731850-3
1) 1) "stream1"					# 读取到了stream1中id大于1681006080120-2的3条消息(如果有多条则读取最新的消息)
   2) 1) 1) "1681006080120-3"
         2) 1) "name"
            2) "Davie"
      2) 1) "1681006080120-4"
         2) 1) "name"
            2) "Eric"
      3) 1) "1681008731850-0"
         2) 1) "name"
            2) "Jack"
2) 1) "stream2"					# stream2中有两条id大于1681008731850-3的消息
   2) 1) 1) "1681008731850-4"
         2) 1) "5"
            2) "five"
      2) 1) "1681008731850-5"
         2) 1) "6"
            2) "six"



# 加入阻塞选项,此时开启另一个redis客户端存入消息到stream1中,观察当前客户端的变化
127.0.0.1:6379> XREAD count 3 block 0 streams stream1 $
1) 1) "stream1"
   2) 1) 1) "1681008731850-0"	# 读取到了一条消息
         2) 1) "name"
            2) "Jack"
(53.24s)	# 等待了53.24s

消费组相关指令

2.9.8XGROUP

XGROUP CREATE key group <id | $> :创建消费者组。

最后一个参数是要考虑已传递的流中最后一项的ID。

$表示从Stream尾部开始消费,在这种情况下,从该消费者组获取数据的消费者只能看到到达流的新元素。

0表示从Stream头部开始消费,消费者组可以获取整个流的历史记录。

创建消费者组的时候必须指定 ID, ID 为 0 表示从头开始消费,为 $ 表示只消费新的消息。

# 创建消费者组
127.0.0.1:6379> XGROUP create mystream1 groupA $
OK
127.0.0.1:6379> XGROUP create mystream1 groupB 0
OK

XGROUP CREATECONSUMER key group consumer:创建消费者。

127.0.0.1:6379> XGROUP CREATECONSUMER mystream1 groupA consumerA	#在流mystream1的groupA中创建消费者consumerA
(integer) 1
127.0.0.1:6379> XINFO CONSUMERS mystream1 groupA	# 查看流mystream1的消费组groupA的消费者信息
1) 1) "name"
   2) "consumerA"	# 消费者名称
   3) "pending"		
   4) (integer) 0	# 消费者读取消息的数量(此时还未读取消息,所以为0)
   5) "idle"
   6) (integer) 26277

XGROUP DESTORY key group:删除流key中指定的消费组。

127.0.0.1:6379> XGROUP create mystream1 groupC 0	# 在流stream1中创建消费组groupC
OK
# 删除消费组
127.0.0.1:6379> XGROUP DESTROY mystream1 groupC	# 删除流stream1中的消费组groupC
(integer) 1		# 返回删除的个数

XGROUP DELCONSUMER key group consumer:删除流key中消费组group的指定消费者。

127.0.0.1:6379> XGROUP CREATECONSUMER mystream1 groupA consumerA
(integer) 1
127.0.0.1:6379> XGROUP DELCONSUMER mystream1 groupA consumerA
(integer) 0		
127.0.0.1:6379> XINFO CONSUMERS mystream1 groupA
(empty array)	# 消费者consumerA已经被删除

2.9.9XREADGROUP

XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] id [id ...]

读取消费者组中的消息。

消费者不存在则自动创建该消费者。

特殊ID:>表示从第一条未被消费的消息开始读取。

# 创建消费组
127.0.0.1:6379> XGROUP create stream1 groupA 0
ok
127.0.0.1:6379> XGROUP create stream1 groupB 0
OK

# 消费组groupA内的消费者consumer1从stream1消息队列中读取所有信息
127.0.0.1:6379> XREADGROUP GROUP groupA consumer1 STREAMS stream1  >	# >表示从第一条未被消费的消息开始读取。
1) 1) "stream1"
   2) 1) 1) "1681006080120-0"
         2) 1) "name"
            2) "Alice"
      2) 1) "1681006080120-1"
         2) 1) "name"
            2) "Bob"
      3) 1) "1681006080120-2"
         2) 1) "name"
            2) "Cindy"
      4) 1) "1681006080120-3"
         2) 1) "name"
            2) "Davie"
      5) 1) "1681006080120-4"
         2) 1) "name"
            2) "Eric"
      6) 1) "1681008731850-0"
         2) 1) "name"
            2) "Jack"
# 消费组groupA中消费者consumer1一口气读取完所有消息,组中其他消费者就不能读取消息了(同一个消费组里的消费者不能消费同一条消息)
127.0.0.1:6379> XREADGROUP GROUP groupA consumer2 STREAMS stream1  >	
(nil)	# 已经被消费者cumstomer1消费完了,所以返回nil



# 创建消费组
127.0.0.1:6379> XGROUP create stream2 groupA 0
OK
127.0.0.1:6379> XGROUP create stream2 groupB 0
OK
# 让组内的多个消费者共同分担读取消息,所以让每个消费者读取部分消息,从而实现消息读取负载在多个消费者间是均衡分布的
127.0.0.1:6379> XREADGROUP GROUP groupA consumer1 count 3 STREAMS stream2 >		# 限制读取3个
1) 1) "stream2"
   2) 1) 1) "1681008731850-0"
         2) 1) "1"
            2) "one"
      2) 1) "1681008731850-1"
         2) 1) "2"
            2) "two"
      3) 1) "1681008731850-2"
         2) 1) "3"
            2) "three"
127.0.0.1:6379> XREADGROUP GROUP groupA consumer2 count 3 STREAMS stream2 >		# 读取另外三个
1) 1) "stream2"
   2) 1) 1) "1681008731850-3"
         2) 1) "4"
            2) "four"
      2) 1) "1681008731850-4"
         2) 1) "5"
            2) "five"
      3) 1) "1681008731850-5"
         2) 1) "6"
            2) "six"
127.0.0.1:6379> XREADGROUP GROUP groupA consumer3 count 3 STREAMS stream2 >
(nil)		# 已经没有消息可读,返回nil

2.9.10XPENDING

XPENDING key group:返回待处理消息相关信息。(读取到的消息没有经过XACK确认即为待处理消息)

返回一组数据,包括消费组待处理消息的数量、所有消费者读取的消息最小id、所有消费者所读取id的最大值、每个消费者待处理消息的数量。

127.0.0.1:6379> XPENDING stream1 groupA
1) (integer) 6			# 待处理消息数
2) "1681006080120-0"	# 待处理消息最小id
3) "1681008731850-0"	# 待处理消息最大id
4) 1) 1) "consumer1"	# 消费者consumer1
      2) "6"			# 消费者consumer1有6条待处理消息
127.0.0.1:6379> XPENDING stream2 groupA
1) (integer) 6			# 待处理消息数
2) "1681008731850-0"	# 待处理消息最小id
3) "1681008731850-5"	# 待处理消息最大id
4) 1) 1) "consumer1"	# 消费者consumer1
      2) "3"			# 消费者consumer1有3条待处理消息
   2) 1) "consumer2"	# 消费者consumer2
      2) "3"			# 消费者consumer2有3条待处理消息

XPENDING key group start end count consumer:查看指定消费者具体读取了哪些数据

# 查看消费者consumer1具体读取了哪些数据
127.0.0.1:6379> XPENDING stream2 groupA - + 5 consumer1	# 查看groupA组consumer1具体读取了哪些数据,设置最大返回5条
1) 1) "1681008731850-0"
   2) "consumer1"
   3) (integer) 2089450
   4) (integer) 1
2) 1) "1681008731850-1"
   2) "consumer1"
   3) (integer) 2089450
   4) (integer) 1
3) 1) "1681008731850-2"
   2) "consumer1"
   3) (integer) 2089450
   4) (integer) 1

2.9.11XACK

XACK key group id [id ...]:向消息队列确认id对应的消息已处理完成,XACK会从待处理消息列表中删除该消息。

返回值:该命令返回成功确认的消息数。

127.0.0.1:6379> XACK stream1 groupA 1681006080120-0	# 确认id1681006080120-0处理完成
(integer) 1		# 成功确认一条
127.0.0.1:6379> XPENDING stream1 groupA
1) (integer) 5	# 待确认消息数减1
2) "1681006080120-1"
3) "1681008731850-0"
4) 1) 1) "consumer1"
      2) "5"

2.9.12XINFO

XINFO stream key:获取流key的详细信息。

127.0.0.1:6379> XINFO stream stream2 	# 获取流stream2的详细信息
 1) "length"
 2) (integer) 6
 3) "radix-tree-keys"
 4) (integer) 1
 5) "radix-tree-nodes"
 6) (integer) 2
 7) "last-generated-id"
 8) "1681008731850-5"
 9) "max-deleted-entry-id"
10) "0-0"
11) "entries-added"
12) (integer) 6
13) "recorded-first-entry-id"
14) "1681008731850-0"
15) "groups"
16) (integer) 2
17) "first-entry"
18) 1) "1681008731850-0"
    2) 1) "1"
       2) "one"
19) "last-entry"
20) 1) "1681008731850-5"
    2) 1) "6"
       2) "six"

XINFO GROUPS key:获取流key中消费组信息

127.0.0.1:6379> XINFO GROUPS stream2	# 获取流stream2中的消费组信息
1)  1) "name"
    2) "groupA"		# 消费组groupA
    3) "consumers"
    4) (integer) 2
    5) "pending"
    6) (integer) 6
    7) "last-delivered-id"
    8) "1681008731850-5"
    9) "entries-read"
   10) (integer) 6
   11) "lag"
   12) (integer) 0
2)  1) "name"
    2) "groupB"		# 消费组groupB
    3) "consumers"
    4) (integer) 1
    5) "pending"
    6) (integer) 3
    7) "last-delivered-id"
    8) "1681008731850-2"
    9) "entries-read"
   10) (integer) 3
   11) "lag"
   12) (integer) 3

XINFO CONSUMERS key group:获取流key中消费组group中消费者信息

127.0.0.1:6379> XINFO CONSUMERS stream2 groupA	# 获取流stream2中消费组groupA中的消费者信息
1) 1) "name"
   2) "consumer1"
   3) "pending"
   4) (integer) 3
   5) "idle"
   6) (integer) 30195569
2) 1) "name"
   2) "consumer2"
   3) "pending"
   4) (integer) 3
   5) "idle"
   6) (integer) 30166362

2.10Bitfield

位域

Bitfield结构的底层也是String类型。

Redis位字段允许设置、递增和获取任意位长度的整数值。例如可以对从无符号1位整数到有符号63位整数的任何数字进行操作。

这些值使用二进制编码的Redis字符串存储。位字段支持原子读、写和递增操作,这使它们成为管理计数器和类似数值的好选择。

例如 hello 等价于 0110100001100101011011000110110001101111,每八位对应一个字母,也对应一个十进制值。可以修改每一位的数字从而改变对应的数值从而改变对应的字母。

Bitfield结构的常用命令:

2.10.1BITFIELD

BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment]
[OVERFLOW WRAP|SAT|FAIL]

此命令会把Redis字符串当作位数组,并能对变长位宽和任意未字节对齐的指定整型位域进行寻址。

下面是已支持的命令列表:

  • GET :返回指定的位域的数值。
  • SET : 设置指定位域的数值并返回它的原值。
  • INCRBY : 自增或自减(如果increment为负数)指定位域的值并返回它的新值。

type表示多少位的有符号还是无符号整型。有符号整型需在位数前加i,无符号在位数前加u。例如,u8是一个8位的无符号整型,i16是一个16位的有符号整型。offset表示偏移量,比如i4表示以4个比特位为一个偏移量。

还有一个命令通过设置溢出行为来改变调用INCRBY指令的后序操作:OVERFLOW [WRAP|SAT|FAIL]

wrap:使用回环方式处理有符号整数和无符号整数的溢出情况。
sat:使用饱和计算方式处理溢出,下溢计算的结果为最小的整数值,上溢计算的结果为最大的整数值。
fail:命令将拒绝执行那些会导致上溢或者下溢情况出现的计算,并向用户返回空值表示计算未被执行。

有符号整型最大支持64位,而无符号整型最大支持63位。对无符号整型的限制,是由于当前Redis协议不能在响应消息中返回64位无符号整数。

字母数值二进制(高位->低位)
h1040110 1000
e1010110 0101
l1080110 1100
l1080110 1100
o1110110 1111
x1200111 1000
  • GET和SET选项
127.0.0.1:6379> set mybitfield hello
OK
127.0.0.1:6379> BITFIELD mybitfield get i8 0	# 以8位位一组,偏移量0表示第一个字符
1) (integer) 104	# 返回该字符对应的十进制值数值
127.0.0.1:6379> BITFIELD mybitfield get i8 8	# 偏移量8表示第二个字符
1) (integer) 101
127.0.0.1:6379> BITFIELD mybitfield get i8 16
1) (integer) 108
127.0.0.1:6379> BITFIELD mybitfield get i8 24
1) (integer) 108
127.0.0.1:6379> BITFIELD mybitfield get i8 32
1) (integer) 111
127.0.0.1:6379> BITFIELD mybitfield set i8 32 120	#将偏移量为32的那一组的数值替换为120(字母x)
1) (integer) 111
127.0.0.1:6379> get mybitfield
hellx
  • INCRBY选项
127.0.0.1:6379> set fieldkey hello
OK
127.0.0.1:6379> BITFIELD fieldkey incrby u4 2 1	# 从第三个比特位开始,对接下来的4位无符号数加1
1) (integer) 11		# 返回指定域增加后的数值
127.0.0.1:6379> get fieldkey	# 因为比特位的数值发生了变化,所以对应的数值也会发生变化,对应的字母也就变了
lello
127.0.0.1:6379> BITFIELD fieldkey incrby u4 2 1
1) (integer) 12
127.0.0.1:6379> BITFIELD fieldkey incrby u4 2 1
1) (integer) 13
127.0.0.1:6379> BITFIELD fieldkey incrby u4 2 1
1) (integer) 14
127.0.0.1:6379> BITFIELD fieldkey incrby u4 2 1
1) (integer) 15
127.0.0.1:6379> BITFIELD fieldkey incrby u4 2 1	# 4位表示最大的数为15,溢出控制默认为wrap(循环溢出),超出后从0开始
1) (integer) 0	# 从0开始
  • OVERFLOW选项
127.0.0.1:6379> set fieldkey2 a
OK
127.0.0.1:6379> BITFIELD fieldkey2 overflow sat set i8 0 126	# 从偏移量0开始后八位对应的数值改为126
1) (integer) 97		# 返回之前的数值
127.0.0.1:6379> get fieldkey2
"~"					# 126对应这个~符号
127.0.0.1:6379> BITFIELD fieldkey2 overflow sat set i8 0 128	# 将数值改为128(超出了8位表示的最大值127)
1) (integer) 126	# 返回之前的数值
127.0.0.1:6379> get fieldkey2
"\x7f"				# 127对应的编码
127.0.0.1:6379> BITFIELD fieldkey2 overflow sat set i8 0 128	# 再次改为128
1) (integer) 127	# 使用sat溢出控制,超出了最大值的表示范围会取最大值127
127.0.0.1:6379> BITFIELD fieldkey2 overflow fail set i8 0 128	# 使用fail溢出控制,再次改为128
1) (nil)			# 使用fail溢出控制,超出了最大值的表示范围返回nil

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android笔记(二十九):利用python自动生成多语言

背景 项目需要支持十几种多语言&#xff0c;而且每个版本的新功能ui都有很多地方需要多语言&#xff0c;如果手动添加非常耗时&#xff0c;于是设计了一个python脚本&#xff0c;通过excel表格转化多语言到项目values/strings文件内 步骤 android工程项目结构 脚本位于langu…

Unity实现用WASD控制一个物体前后左右移动-小白课程01

1 根据业务逻辑搭建场景 02 根据业务写代码 using System.Collections; using System.Collections.Generic; using UnityEngine;//实现让被挂在的物体往前移动 //按下W键往前移动&#xff0c;按下S键往后移动 public class RoleMove : MonoBehaviour { public float myspe…

Enterprise Architect15(EA) 工具栏,隐藏后显示快捷方式

没有工具栏 显示工具栏 快捷键&#xff1a;ctrl shift 3 或者Design-->点击ToolBox 工具栏中直接拖动即可创建对应的元素&#xff1a;

springboot集成qq邮箱

1.maven依赖 <!-- email依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency><dependency><groupId>org.springframework.boot</group…

seata的部署和集成:部署Seata的tc-server、微服务集成seata、TC服务的高可用和异地容灾

seata的部署和集成 一、部署Seata的tc-server 1.下载 首先我们要下载seata-server包&#xff0c;地址在http&#x1f615;/seata.io/zh-cn/blog/download.html 当然&#xff0c;课前资料也准备好了&#xff1a; 2.解压 在非中文目录解压缩这个zip包&#xff0c;其目录结构…

git 合并分支某次(commit)提交

需求&#xff1a;将develop分支某次提交合并到master上面&#xff0c;其他修改不同步&#xff1b; //切换到master分支 git checkout master //查看develop分支提交记录&#xff0c;获取对应记录哈希值&#xff1b; git log develop // 按上下按钮可以上下查询对应记录&#xf…

分享一个python实验室设备预约管理系统 实验室设备维修系统源码 lw 调试

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

【Word】页眉编辑小技巧

页眉编辑小技巧 1 奇偶页不同2 仅设置正文有页眉3 页眉设置信息为章节内容参考 1 奇偶页不同 2 仅设置正文有页眉 1、定位到目录页之后&#xff0c;点击“布局——分隔符——分节符中的下一页”&#xff0c;在目录页和正文之间插入一个分节符&#xff0c;使得目录页和正文成为…

YOLOv5算法改进(16)— 增加小目标检测层

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。小目标检测层是指在目标检测任务中用于检测小尺寸目标的特定网络层。由于小目标具有较小的尺寸和低分辨率&#xff0c;它们往往更加难以检测和定位。YOLOv5算法的检测速度与精度较为平衡&#xff0c;但是对于小目标的检测效…

[管理与领导-85]:IT基层管理者 - 核心技能 - 高效执行力 - 10 - 高效执行力的9个段位

目录 前言&#xff1a; 一段&#xff1a;准确执行&#xff0c;快速反应&#xff0c;坚决执行 &#xff08;态度很重要&#xff09; 二段&#xff1a;结果导向 苦劳过后&#xff0c;有功劳&#xff08;有结果很重要&#xff09; 三段&#xff1a;有始有终 主动反馈、有始有终…

Prometheus 监控指南:如何可靠地记录数字时间序列数据

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f6e0;️ 全栈技术 Full Stack: &#x1f4da…

《TCP/IP网络编程》阅读笔记--多播与广播

目录 1--多播 2--多播代码实例 3--广播 4--广播代码实例 1--多播 多播方式的数据传输是基于 UDP 完成的&#xff0c;多播数据包的格式与 UDP 数据包相同&#xff1b; 多播与 UDP 的区别&#xff1a;UDP 数据传输以单一目标进行&#xff0c;多播数据同时传递到加入&#xff…

【数据结构】红黑树的插入与验证

文章目录 一、基本概念1.时代背景2. 基本概念3.基本性质 二、实现原理1. 插入1.1变色1.2旋转变色①左旋②右旋③右左双旋④左右双旋 2.验证 源码总结 一、基本概念 1.时代背景 1972年鲁道夫拜尔(Rudolf Bayer)发明了一种数据结构&#xff0c;这是一种特殊的B树4阶情况。这些树…

基于SSM的学生公寓管理中心系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Geotif.js读取tif元信息相关问题记录

起因是使用OL加载COG时&#xff0c;出现了不指定sources的max就一片黑的情况&#xff0c;所以需要读取tif真实波段值范围而不是靠比例设置颜色了。 使用geotiff.js可以读取tif的元信息&#xff0c;但当tif没有GDAL_METADATA这个key时就读不出来 然后找到了这个 乍一看简直完美…

普中 51 单片机点亮LED灯

普中 51 单片机 &#xff08;STC89C52RC&#xff09; LED / IO 将LED1进行闪烁操作 为啥要进行延时操作&#xff1f;依据人的肉眼余晖效应&#xff0c; 延时时间不能太短&#xff0c;否则就无法观察到 LED 闪烁 #include "reg52.h" typedef unsigned int u16; //对…

【Linux】Base64编码

Mz1 对这3个字符进行一个Base64编码理解&#xff0c;把他化为2进制数据&#xff0c;在以6个位为单位分割&#xff0c;然后用这个16进制化为10进制&#xff0c;查表得出阿斯卡码对应的字符&#xff0c;那么这个字符就是base64编码&#xff0c;因为64个字符有64阿斯卡码。 相关截…

SpringBoot学习笔记(项目创建,yaml,多环境开发,整合mybatis SMM)

一、SpringBoot入门 1.1 SpringBoot概述 SpringBoot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化Spring应用的初始搭建以及开发过程。 Spring程序缺点&#xff1a;配置繁琐&#xff0c;依赖设置繁琐。SpringBoot程序优点&#xff1a;自动装配&#xff0c…

列表对象复制属性到另一个列表对象 从List<Object>另一个List<Object>

目录 事件起因环境和工具解决办法结束语 事件起因 在写一个市级的项目时&#xff0c;遇到了一个问题&#xff0c;这个项目涉及的数据内容非常大&#xff0c;光是数据库文件的大小就已经达到了12G&#xff0c;数据的规模大致是在百万级的&#xff0c;光是我这次参与处理的数据就…

led灯白光和暖光哪个对眼睛好?最适合孩子开学使用的护眼台灯

什么样的光更适合阅读呢&#xff1f;从生物学的角度上讲是早上的自然光。一方面是因为早晨的光照使得人体内在的生物钟和外界24h亮暗循环同步。如果生理节律被打乱&#xff0c;早晨明亮的光照可以帮助恢复正常的生理节律。另一方面是其物理特性&#xff0c;自然光漫射效果较好&…