前置内容

启动Redis
[root@localhost src]# cd /usr/local/redis-6.2.6/src 进入redis文件夹的src目录里
[root@localhost src]# ./redis-server ../redis.conf
[root@localhost src]# ./redis-cli 启动进程
查看线程
ps -fe | grep redis
结束进程
cd /…/redis-6.2.6/src redis安装地方
./redis-cli 进入redis
关闭redis服务:shutdown
退出客户端:exit
查看服务端口
netstat -lanp | grep 6379

Redis开发文档
https://www.redis.com.cn/tutorial.html
通过这个网站学习各类的存储方式
https://db-engines.com/en/articlesimage.png

一、Redis中values类型 字符串

set、get、mset、mget

Redis SET 命令
用于将键 key 设定为指定的“字符串”值。
如果 key 已经保存了一个值,那么这个操作会直接覆盖原来的值,并且忽略原始类型。
当 set 命令执行成功之后,之前设置的过期时间都将失效
Redis GET 命令
返回与键 key 相关联的字符串值,用于获取指定 key 的值。
如果键 key 不存在, 那么返回特殊值 nil ; 否则, 返回键 key 的值。
如果键 key 的值不是字符串类型, 那么返回一个错误, 因为 GET 命令只能用于字符串值。
Redis MSET 命令
设置多个 key 的值为各自对应的 value。
MSETSET 一样,会用新值替换旧值。如果你不想覆盖旧值,可以使用 MSETNX
MSET 是原子操作,所有 key 的值同时设置。客户端不会看到有些 key 值被修改,而另一些 key 值没变。
Redis MGET 命令
返回所有(一个或多个)给定 key 的值,值的类型是字符串。 如果给定的 key 里面,有某个 key 不存在或者值不是字符串,那么这个 key 返回特殊值 nil 。
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> help set
SET key value [EX seconds|PX milliseconds|EXAT timestamp|PXAT milliseconds-timestamp|KEEPTTL] [NX|XX][GET]
summary: Set the string value of a key
since: 1.0.0
group: string
127.0.0.1:6379> set k1 hello
OK
127.0.0.1:6379> get k1
“hello”
127.0.0.1:6379> set k1 newHello nx #nx 指k1没有值的情况下新建newHello值 nx只能新建
(nil)
127.0.0.1:6379> get k1
“hello”
127.0.0.1:6379>
[root@localhost src]# ./redis-cli
127.0.0.1:6379> get k1
“hello”
127.0.0.1:6379> set k2 aaa xx #xx 指k2存在的情况下更新aaa值 xx只能更新
(nil)
127.0.0.1:6379> get k2
(nil)
127.0.0.1:6379>
127.0.0.1:6379> mset key value [key value …] #提示可以设置多个键值对
127.0.0.1:6379> mset k3 a k4 b
OK
127.0.0.1:6379> get k3
“a”
127.0.0.1:6379> get k4
“b”
127.0.0.1:6379> mget key [key …] #提示可以获取多个键对应的值
127.0.0.1:6379> mget k3 k4
1) “a”
2) “b”
127.0.0.1:6379>

APPEND key value

Redis APPEND 命令
用于为指定的 key 追加值。
如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。
如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。
返回值
多行字符串: 返回key中存储的值,key 不存在是返回nil 。
字符串: 如果SET命令正常执行那么回返回OK 多行字符串: 使用 GET 选项,返回 key 存储的值,如果 key 不存在返回空 : 否则如果加了NX 或者 XX选项,SET 没执行,那么会返回nil。
字符串: 总是返回“OK”,因为 MSET 不会失败。
数组: MGET 命令将返回一个列表, 列表中包含了所有给定键的值。
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> get k1
“hello”
127.0.0.1:6379> APPEND k1 “ world”
(integer) 11
127.0.0.1:6379> get k1
“hello world”
127.0.0.1:6379>

GETRANGE key start end

GETRANGE 命令
返回存储在 key 中的字符串的子串,由 start 和 end 偏移决定(都包括在内)。负数偏移提供相对字符串结尾的偏移。所以, -1 表示最后一个字符, -2 表示倒数第二个字符,以此类推。
GETRANGE 通过将结果范围限制为字符串的实际长度来处理超出范围的请求。
Warning: GETRANGE 是改名而来,在 Redis2.0 以前版本叫做 SUBSTR 。
image.png
返回值
多行字符串:截取得到的子字符串。
——————————————————————————分割线——————————————————————————

127.0.0.1:6379> get k1
“hello world”
127.0.0.1:6379> GETRANGE k1 6 10
“world”
127.0.0.1:6379> GETRANGE k1 6 -1
“world”
127.0.0.1:6379> GETRANGE k1 0 -1
“hello world”

SETRANGE key offset value

SETRANGE 命令
从偏移量 offset 开始, 用 value 参数覆盖键 key 储存的字符串值。
不存在的键 key 当作空白字符串处理。
SETRANGE 命令
SETRANGE 命令会确保字符串足够长以便将 value 设置到指定的偏移量上, 如果键 key 原来储存的字符串长度比偏移量小(比如字符串只有 5 个字符长,但你设置的 offset 是 10 ), 那么原字符和偏移量之间的空白将用零字节(zerobytes, “\x00” )进行填充。
因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内, 所以用户能够使用的最大偏移量为 229-1(536870911) , 如果你需要使用比这更大的空间, 请使用多个 key 。
Warning: 当生成一个很长的字符串时, Redis 需要分配内存空间, 该操作有时候可能会造成服务器阻塞(block)。 在2010年出产的Macbook Pro上, 设置偏移量为 536870911(512MB 内存分配)将耗费约 300 毫秒, 设置偏移量为 134217728(128MB 内存分配)将耗费约 80 毫秒, 设置偏移量 33554432(32MB 内存分配)将耗费约 30 毫秒, 设置偏移量为 8388608(8MB 内存分配)将耗费约 8 毫秒。
返回值
整数: SETRANGE 命令会返回被修改之后, 字符串值的长度。
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> get k1
“hello world”
127.0.0.1:6379> SETRANGE k1 6 xiaohui
(integer) 13
127.0.0.1:6379> get k1
“hello xiaohui”
127.0.0.1:6379>

STRLEN key

Redis Strlen 命令用于获取指定 key 所储存的字符串值的长度。当 key 储存的不是字符串类型时,返回错误。
返回值
整数: 字符串的长度,key 不存在时,返回 0 。 exist.
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> get k1
“hello xiaohui”
127.0.0.1:6379> STRLEN k1
(integer) 13 # 不存在的 key 长度为 0
127.0.0.1:6379> get k2
(nil)
127.0.0.1:6379> STRLEN k2
(integer) 0

DECRBY key decrement

将键 key 储存的整数值减去减量 decrement 。
如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECRBY 命令。
如果键 key 储存的值不能被解释为数字, 那么 DECRBY 命令将返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
关于更多递增(increment) / 递减(decrement)操作的更多信息, 请参见 INCR 命令的文档。
返回值
整数: DECRBY 命令会返回键在执行减法操作之后的值。
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> get k1
“hello xiaohui”
127.0.0.1:6379> DECRBY k1 3
(error) ERR value is not an integer or out of range
127.0.0.1:6379> set k1 10
OK
127.0.0.1:6379> get k1
“10”
127.0.0.1:6379> DECRBY k1 3
(integer) 7

GETSET key value

将键 key 的值设为 value , 并返回键 key 在被设置之前的旧值。
返回给定键 key 的旧值。
如果键 key 没有旧值, 也即是说, 键 key 在被设置之前并不存在, 那么命令返回 nil 。
当键 key 存在但不是字符串类型时, 命令返回一个错误。
返回值
多行字符串: the old value stored at key, or nil when key did not exist.
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> get k1
“hello”
127.0.0.1:6379> getset k1 world
“hello”
127.0.0.1:6379> get k1
“world”

还有很多对字符串的命令,可以参考Redis开发文档进行学习。

二、Redis中values类型 数值

TYPE key

以字符串的形式返回存储在 key 中的值的类型。
可返回的类型是: string, list, set, zset,hash 和 stream。
返回值
字符串: 返回 key 的类型, key 不存在时返回 none。
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> set k1 99
OK
127.0.0.1:6379> get k1
“99”
127.0.0.1:6379> type k1
string

OBJECT subcommand [arguments [arguments …]]

OBJECT 命令允许从内部察看给定 key 的 Redis 对象, 它通常用在除错(debugging)或者了解为了节省空间而对 key 使用特殊编码的情况。 当将Redis用作缓存程序时,你也可以通过 OBJECT 命令中的信息,决定 key 的驱逐策略(eviction policies)。
OBJECT 命令有多个子命令:

  • OBJECT REFCOUNT 返回给定 key 引用所储存的值的次数。此命令主要用于除错。
  • OBJECT ENCODING 返回给定 key 锁储存的值所使用的内部表示(representation)。
  • OBJECT IDLETIME 返回给定 key 自储存以来的空闲时间(idle, 没有被读取也没有被写入),以秒为单位。

对象可以以多种方式编码:

  • 字符串可以被编码为 raw (一般字符串)或 int (为了节约内存,Redis 会将字符串表示的 64 位有符号整数编码为整数来进行储存)。
  • 列表可以被编码为 ziplist 或 linkedlist 。 ziplist 是为节约大小较小的列表空间而作的特殊表示。
  • 集合可以被编码为 intset 或者 hashtable 。 intset 是只储存数字的小集合的特殊表示。
  • 哈希表可以编码为 zipmap 或者 hashtable 。 zipmap 是小哈希表的特殊表示。
  • 有序集合可以被编码为 ziplist 或者 skiplist 格式。 ziplist 用于表示小的有序集合,而 skiplist 则用于表示任何大小的有序集合。

假如你做了什么让 Redis 没办法再使用节省空间的编码时(比如将一个只有 1 个元素的集合扩展为一个有 100 万个元素的集合),特殊编码类型(specially encoded types)会自动转换成通用类型(general type)。
返回值
REFCOUNT 和 IDLETIME 返回数字。 ENCODING 返回相应的编码类型。

  • Subcommands refcount and idletime return integers.
  • Subcommand encoding returns a bulk reply.

——————————————————————————分割线——————————————————————————
127.0.0.1:6379> object help
1) OBJECT [ [value] [opt] …]. Subcommands are:
2) ENCODING
3) Return the kind of internal representation used in order to store the value
4) associated with a .
5) FREQ
6) Return the access frequency index of the . The returned integer is
7) proportional to the logarithm of the recent access frequency of the key.
8) IDLETIME
9) Return the idle time of the , that is the approximated number of
10) seconds elapsed since the last access to the key.
11) REFCOUNT
12) Return the number of references of the value associated with the specified
13) .
14) HELP
15) Prints this help.
127.0.0.1:6379> OBJECT encoding k2
“embstr”
127.0.0.1:6379> get k2
“hello”
127.0.0.1:6379> OBJECT encoding k1
“int”
127.0.0.1:6379> get k1
“99”
127.0.0.1:6379> object refcount k2
(integer) 1
127.0.0.1:6379> object encoding k2
“embstr”
127.0.0.1:6379> object idletime k2
(integer) 161

INCR key

Redis INCR 命令将 key 中储存的数字值增一。
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 ERR ERR hash value is not an integer。
本操作的值限制在 64 位(bit)有符号数字表示之内。
Note: 本质上这是一个字符串操作,因为Redis没有专门的整数类型。存储在 key 中的字符串被转换为十进制有符号整数,在此基础上加1。
返回值
整数: 执行 INCR 命令之后 key 的值。
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> get k1
“99”
127.0.0.1:6379> INCR k1
(integer) 100
127.0.0.1:6379> get k1
“100”

INCRBY key increment

Redis INCRBY 命令将 key 中储存的数字加上指定的增量值。
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令。
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 ERR ERR hash value is not an integer。
本操作的值限制在 64 位(bit)有符号数字表示之内。
关于递增(increment) / 递减(decrement)操作的更多信息, 请参见 INCR 命令的文档。
返回值
整数: 命令执行之后 key 中 存储的值。
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> get k1
“100”
127.0.0.1:6379> incrby k1 22
(integer) 122
127.0.0.1:6379> get k1
“122”

DECR key

为键 key 储存的数字值减去一。
如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECR 操作。
如果键 key 储存的值不能被解释为数字, 那么 DECR 命令将返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
返回值
整数: 执行操作之后key中的值
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> get k1
“122”
127.0.0.1:6379> decr k1
(integer) 121
127.0.0.1:6379> get k1
“121”

DECRBY key decrement

将键 key 储存的整数值减去减量 decrement 。
如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECRBY 命令。
如果键 key 储存的值不能被解释为数字, 那么 DECRBY 命令将返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
关于更多递增(increment) / 递减(decrement)操作的更多信息, 请参见 INCR 命令的文档。
返回值
整数: DECRBY 命令会返回键在执行减法操作之后的值。
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> get k1
“121”
127.0.0.1:6379> decrby k1 21
(integer) 100
127.0.0.1:6379> get k1
“100”

INCRBYFLOAT key increment

为键 key 中储存的值加上浮点数增量 increment ,key 中的浮点数是以字符串形式存储的。
如果键 key 不存在, 那么 INCRBYFLOAT 会先将键 key 的值设为 0 , 然后再执行加法操作。
如果命令执行成功, 那么键 key 的值会被更新为执行加法计算之后的新值, 并且新值会以字符串的形式返回给调用者。
无论是键 key 的值还是增量 increment , 都可以使用像 2.0e7 、 3e5 、 90e-2 那样的指数符号(exponential notation)来表示, 但是, 执行 INCRBYFLOAT 命令之后的值总是以同样的形式储存, 也即是, 它们总是由一个数字, 一个(可选的)小数点和一个任意长度的小数部分组成(比如 3.14 、 69.768 ,诸如此类), 小数部分尾随的 0 会被移除, 如果可能的话, 命令还会将浮点数转换为整数(比如 3.0 会被保存成 3 )。
此外, 无论加法计算所得的浮点数的实际精度有多长, INCRBYFLOAT 命令的计算结果最多只保留小数点的后十七位。
当以下任意一个条件发生时, 命令返回一个错误:

  • 键 key 的值不是字符串类型(因为 Redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型);
  • 键 key 当前的值或者给定的增量 increment 不能被解释(parse)为双精度浮点数。

返回值
多行字符串: 在加上增量 increment 之后, 键 key 的值。
—————————————————————-分割线—————————————————————-
127.0.0.1:6379> get k1
“100”
127.0.0.1:6379> incrbyfloat k1 0.5
“100.5”
127.0.0.1:6379> get k1
“100.5”

FLUSHALL

删除所有数据库里面的所有数据,注意不是当前数据库,而是所有数据库。
这个命令永远不会出现失败。
这个操作的时间复杂度是O(N),N是数据库的数量。
返回
simple-string-reply
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> set k1 helloworld
OK
127.0.0.1:6379> get k1
“helloworld”
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> get k1
(nil)

三、Redis中的二进制安全 **

什么是二进制安全?Redis的String为什么是二进制安全的?
二进制安全是一种主要用于字符串操作函数相关的计算机编程术语。一个二进制安全功能(函数),其本质上将操作输入作为原始的、无任何特殊格式意义的数据流。其在操作上应包含一个字符所能有的256种可能的值(假设为8比特字符)
那么什么是特殊格式呢?
大多数的函数当其使用任何特别的或标记字符,如转义码,那些期望 null 结尾的字符串(如C语言中的字符串),不是二进制安全的。一个可能的例外是该函数的明确的目的是在某二进制字符串搜索某特定字符。
在处理未知格式的数据(尽管此格式无需保存),例如随意的文件、加密数据及类似情况时,二进制安全功能是必须的。函数必须知道数据长度,以便函数操作整体数据。
密码学范畴:
  二进制安全是指,在传输数据时,保证二进制数据的信息安全,也就是不被篡改、破译等,如果被攻击,能够及时检测出来。 二进制安全包含了密码学的一些东西,比如加解密、签名等。
其他解释:
  二进制安全功能(binary-safe function)是指在一个二进制文件上所执行的不更改文件内容的功能或者操作。这能够保证文件不会因为某些操作而遭到损坏。二进制数据是按照一串0和1的形式编码的。而绝大多数的程序会给某些特殊的比特串赋予不同的格式代码,所以当用户使用一个程序读取一个二进制文件时,该文件会被按照这个程序的规则进行解释。如果这个程序所使用的格式编码和文件被写入的格式编码一致,那么这个文件可以被正常读取,否则该文件的格式代码之中会被附加一些无意义的符号,也可能会导致文件损坏。如果最严重的情况发生,这样的操作会因为损坏导致你的数据永久丢失。所以你应该将重要的文件保存在只读性的存储介质上,例如光盘。
  所以根据维基的解释,可以这么理解:
  它并不像C语言那样,使用’\0’作为判定一个字符串的结尾,所以如果你保存的字符串内存在’\0’,c语言自会识别前面的数据,后面的就会被忽略掉,所以说是不安全的。而redis是使用了独立的len,这样可以保证即使存储的数据中有’\0’这样的字符,它也是可以支持读取的。而且前面介绍到Redis的string可以支持各种类型(图片、视频、静态文件、css文件等)。

  1. struct sdshdr{
  2. int len;//buf数组中已经使用的字节的数量,也就是SDS字符串长度
  3. int free;//buf数组中未使用的字节的数量
  4. char buf[];//字节数组,字符串就保存在这里面
  5. };

redis通过定义上述结构体的方式,扩展了C语言底层字符串的缺点,字符串长度的获取时间复杂度从原来的O(N)变成了O(1),另一方面也可以通过free的动态改变来减少内存的分配。
需要强调一点的是buf数组不是存储的字符,而是二进制数组,因为C语言字符串中间是不能出现空字符的,而二进制数据中间很有可能会有空字符,所以C语言是二进制不安全的,而redis又是二进制安全。为了存储多种类型的数据,redis就直接把所有数据当作二进制来存储,这样就可以存储媒体文件和字符串,所以SDS虽然叫简单动态字符串,但是它可不只是用来保存字符串。
SDS在Redis中是实现字符串对象的工具。当你对该字符串取值时是通过len属性判断实际内容的长度,然后取的值。拼接字符串时是追加到free空间中的。
  简单总结:二进制安全的意思就是,只关心二进制化的字符串,不关心具体格式,只会严格的按照二进制的数据存取,不会妄图以某种特殊格式解析数据。
  Redis的简单动态字符串SDS对比C语言的字符串char,有以下特性:
可以在O(1)的时间复杂度得到字符串的长度
可以高效的执行append追加字符串操作
*二进制安全

  原理:SDS通过判断当前字符串空余的长度与需要追加的字符串长度,如果空余长度大于等于需要追加的字符串长度,那么直接追加即可,这样就减少了重新分配内存操作;否则,先用sdsMakeRoomFor函数对SDS进行扩展,按照一定的机制来决定扩展的内存大小,然后再执行追加操作,扩展后多余的空间不释放,方便下次再次追加字符串,这样做的代价就是浪费了一些内存,但是在Redis字符串追加操作很频繁的情况下,这种机制能很高效的完成追加字符串的操作。

**在使用Redis的时候,要在用户端沟通好数据的编码和字节码,Redis中没有数据类型

四、Redis中values类型 bitmap

SETBIT key offset value

Redis Setbit 命令用于对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
根据值 value 是 1 或 0 来决定设置或清除位 bit。当 key 不存在时会创建一个新的字符串。
当字符串不够长时,字符串的长度将增大,以确保它可以在offset位置存储值。
offset 参数需要大于等于0,并且小于 232 (bitmaps 最大 512MB)。
当值字符串变长时,添加的 bit 会被设置为 0。
注意: 当设置的是最后一位 bit (offset 等于 232 -1),并且存储在 key 中的字符串还没有存储一个字符串值,或者存储的是一个短的字符串值时,Redis 需要分配所有的中间内存,这会阻塞 Redis 服务器一段时间。
在 2010 年的 MacBook Pro上,设置 232 -1 位 (分配512MB内存) 需花费 300ms,设置 230 -1 位 (分配 128MB 内存) 需花费 80m,设置 228 -1 位 (分配 32MB 内存) 需花费 30ms,设置 226 -1 位 (分配 8MB 内存) 需花费 8ms。
需要注意的是,一旦上面第一步内存分配被完成,对于同一个 key 接下来调用 SETBIT 将不会有分配内存开销。
字符集 ascii
其他一般叫做扩展字符集
扩展: 其他字符集不在对ascii重编码
0xxxxxxx
你自己写一个程序,字节流读取,每字节判断
返回值
整数: 存储在 offset 偏移位的原始值
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> setbit k1 1 1
(integer) 0
127.0.0.1:6379> strlen k1
(integer) 1
127.0.0.1:6379> get k1
“@”
image.png

BITCOUNT key [start end]

统计字符串被设置为1的bit数.
一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。
start 和 end 参数的设置和 GETRANGE 命令类似,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,以此类推。
不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。
返回值
整数
被设置为 1 的位的数量。
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> set k2 “helloworld”
OK
127.0.0.1:6379> bitcount k2
(integer) 44
127.0.0.1:6379> bitcount k2 0 0
(integer) 3
127.0.0.1:6379> bitcount k2 1 1
(integer) 4
127.0.0.1:6379> get k2
“helloworld”

BITOP operation destkey key [key …]

对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种参数:

  • BITOP AND destkey srckey1 srckey2 srckey3 … srckeyN ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。
  • BITOP OR destkey srckey1 srckey2 srckey3 … srckeyN,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。
  • BITOP XOR destkey srckey1 srckey2 srckey3 … srckeyN,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。
  • BITOP NOT destkey srckey,对给定 key 求逻辑非,并将结果保存到 destkey 。

除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入。
执行结果将始终保持到destkey里面。
处理不同长度的字符串
当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0 。
空的 key 也被看作是包含 0 的字符串序列。
返回值
整数
保存到 destkey 的字符串的长度,和输入 key 中最长的字符串长度相等。
——————————————————————————分割线——————————————————————————
127.0.0.1:6379> setbit k1 1 1
0
127.0.0.1:6379> setbit k1 7 1
0
127.0.0.1:6379> get k1
A
127.0.0.1:6379> setbit k2 1 1
0
127.0.0.1:6379> setbit k2 6 1
0
127.0.0.1:6379> get k2
B
127.0.0.1:6379> bitop and andkey k1 k2
1
127.0.0.1:6379> get andkey
@
127.0.0.1:6379> bitop or orkey k1 k2
1
127.0.0.1:6379> get orkey
C

image.png

实例应用

用户系统,统计用户登录天数,且窗口随机

127.0.0.1:6379> setbit sean 1 1
(integer) 0
127.0.0.1:6379> setbit sean 7 1
(integer) 0
127.0.0.1:6379> setbit sean 364 1
(integer) 0
127.0.0.1:6379> strlen sean
(integer) 46
127.0.0.1:6379> bitcount sean -2 -1
(integer) 1
image.png

送礼物时,大库备货多少,假设有2E用户

127.0.0.1:6379> setbit 20220301 1 1 第一天a用户
(integer) 0
127.0.0.1:6379> setbit 20220302 1 1 第二天a用户
(integer) 0
127.0.0.1:6379> setbit 20220302 7 1 地二天b用户
(integer) 0
127.0.0.1:6379> bitop or destkey 20220301 20220302
(integer) 1
127.0.0.1:6379> bitcount destkey
(integer) 2
image.png

常见面试题

1、SDS如何兼容C语言字符串?如何保证二进制安全?
SDS对象中的buf是一个柔性数组,上层调用时,SDS直接返回了buf。由于buf是直接指向内容的指针,所以兼容C语言函数。而当真正读取内容时,SDS会通过len来限制读取长度,而非“\0”,所以保证了二进制安全。
2、sdshdr5的特殊之处是什么?
sdshdr5只负责存储小于32字节的字符串。一般情况下,小字符串的存储更普遍,所以Redis进一步压缩了sdshdr5的数据结构,将sdshdr5的类型和长度放入了同一个属性中,用flags的低3位存储类型,高5位存储长度。创建空字符串时,sdshdr5会被sdshdr8替代。
3、SDS是如何扩容的?
SDS在涉及字符串修改时会调用sdsMakeroomFor函数进行检查,会根据空闲长度和新增内容的长度进行比较判断,然后根据不同情况动态扩容,该操作对上层透明。(具体扩容步骤比较复杂,此处暂不展开讨论,有兴趣的同学可自行研究)

01Redis前无古人后无来者.svg
[

](https://blog.csdn.net/weixin_41018580/article/details/107179631)