字符串类型是redis最基础的数据结构。首先键都是字符串类型,而且其他几种数据结构都是在字符串类型基础上构建的,所以字符串类型能为其他四种数据结构的学习奠定基础。字符串类型的值实际可以是字符串(简单的字符串、复杂的字符串(例如JSON、XML)、数字(整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能超过512MB。
未研究命令:
实战场景:
set key value [EX seconds] [PX milliseconds] [NX|XX]
将字符串值 value 关联到 key
如果 key 已经持有其他值, SET 就覆写旧值,无视类型。
对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。
可选参数
EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
XX :只在键已经存在时,才对键进行设置操作。
因为 SET 命令可以通过参数来实现和 SETNX 、 SETEX 和 PSETEX 三个命令的效果,所以将来的 Redis 版本可能会废弃并最终移除 SETNX 、 SETEX 和 PSETEX 这三个命令。
#如果 key 已经持有其他值, SET 就覆写旧值,无视类型
127.0.0.1:6379> set hello 123
OK
127.0.0.1:6379> get hello
"123"
127.0.0.1:6379> set hello qwe
OK
127.0.0.1:6379> get hello
"qwe"
#对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除
#EX second :设置键的过期时间为 second 秒
127.0.0.1:6379> set hello 123 ex 10086
OK
127.0.0.1:6379> ttl hello
(integer) 10080
127.0.0.1:6379> set hello ewew
OK
127.0.0.1:6379> ttl hello
(integer) -1
mset key value [key value ...]
:同时设置一个或多个 key-value 对。
如果某个给定 key 已经存在,那么 MSET 会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用 MSETNX 命令:它只会在所有给定 key 都不存在的情况下进行设置操作。
MSET 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,某些给定 key 被更新而另一些给定 key 没有改变的情况,不可能发生。
返回值:总是返回 OK (因为 MSET 不可能失败)
127.0.0.1:6379> mset w1 sasa w2 wewe
OK
127.0.0.1:6379> get w1
"sasa"
127.0.0.1:6379> get w2
"wewe"
getset key value
:将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
当 key 没有旧值时,也即是, key 不存在时,返回 nil
当 key 存在但不是字符串类型时,返回一个错误。
127.0.0.1:6379> GETSET db mongodb # 没有旧值,返回 nil
(nil)
127.0.0.1:6379> GET db
"mongodb"
127.0.0.1:6379> GETSET db redis # 返回旧值 mongodb
"mongodb"
127.0.0.1:6379> GET db
"redis"
get key:
返回 key 所关联的字符串值。当 key 不存在时,返回 nil ,否则,返回 key 的值
如果 key 不是字符串类型,那么返回一个错误
# 对不存在的 key 或字符串类型 key 进行 GET
127.0.0.1:6379> GET db
(nil)
127.0.0.1:6379> SET db redis
OK
127.0.0.1:6379> GET db
"redis"
# 对不是字符串类型的 key 进行 GET
127.0.0.1:6379> DEL db
(integer) 1
127.0.0.1:6379> LPUSH db redis mongodb mysql
(integer) 3
127.0.0.1:6379>GET db
(error) ERR Operation against a key holding the wrong kind of value
getrange key start end
:返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)
负数偏移量表示从字符串最后开始计数, -1 表示最后一个字符, -2 表示倒数第二个,以此类推。返回截取得出的子字符串。
127.0.0.1:6379> SET greeting "hello, my friend"
OK
127.0.0.1:6379> getrange greeting 0 4 # 返回索引0-4的字符,包括4。
"hello"
127.0.0.1:6379> getrange greeting -1 -5 # 不支持回绕操作
""
127.0.0.1:6379> getrange greeting -3 -1 # 负数索引
"end"
127.0.0.1:6379> getrange greeting 0 -1 # 从第一个到最后一个
"hello, my friend"
127.0.0.1:6379> getrange greeting 0 1008611 # 值域范围不超过实际字符串,超过部分自动被符略
"hello, my friend"
mget key [key ...]
返回所有(一个或多个)给定 key 的值。
如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。
127.0.0.1:6379> mget redis mongodb mysql # 不存在的 mysql 返回 nil
1) "redis.com"
2) "mongodb.org"
3) (nil)
strlen key
:返回 key 所储存的字符串值的长度。当 key 储存的不是字符串值时,返回一个错误。
127.0.0.1:6379> strlen clyu
(integer) 6
append key value
:追加字符串,返回追加 value 之后, key 中字符串的长度
如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。
如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。
127.0.0.1:6379> get clyu
"123"
127.0.0.1:6379> append clyu qwe
(integer) 6
127.0.0.1:6379> get clyu
"123qwe"
setrange key offset value
:指定区域更新,返回值:被 SETRANGE 修改之后,字符串的长度。
不存在的 key 当作空白字符串处理
SETRANGE 命令会确保字符串足够长以便将 value 设置在指定的偏移量上,如果给定 key 原来储存的字符串长度比偏移量小(比如字符串只有 5 个字符长,但你设置的 offset 是 10 ),那么原字符和偏移量之间的空白将用零字节(zerobytes, “\x00” )来填充。
注意你能使用的最大偏移量是 2^29-1(536870911) ,因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内。如果你需要使用比这更大的空间,你可以使用多个 key 。
当生成一个很长的字符串时,Redis 需要分配内存空间,该操作有时候可能会造成服务器阻塞(block)。在2010年的Macbook Pro上,设置偏移量为 536870911(512MB 内存分配),耗费约 300 毫秒, 设置偏移量为 134217728(128MB 内存分配),耗费约 80 毫秒,设置偏移量 33554432(32MB 内存分配),耗费约 30 毫秒,设置偏移量为 8388608(8MB 内存分配),耗费约 8 毫秒。 注意若首次内存分配成功之后,再对同一个 key 调用 SETRANGE 操作,无须再重新内存。
redis> set greeting "hello world"
OK
redis> setrange greeting 6 "Redis"
(integer) 11
redis> get greeting
"hello Redis"
incr key
:将 key 中储存的数字值增一
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
这是一个针对字符串的操作,因为 Redis 没有专用的整数类型,所以 key 内储存的字符串被解释为十进制 64 位有符号整数来执行 INCR 操作。
127.0.0.1:6379> set number 123
OK
127.0.0.1:6379> incr number
(integer) 124
incrby key increment
:将 key 所储存的值加上增量 increment 。
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令。
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
127.0.0.1:6379> get number
"124"
127.0.0.1:6379> incrby number 10
(integer) 134
127.0.0.1:6379> get number
"134"
incrbyfloat key increment :为 key 中所储存的值加上指定的浮点数增量值
如果 key 不存在,那么 incrbyfloat 会先将 key 的值设为 0 ,再执行加法操作
127.0.0.1:6379> incrbyfloat float 1
"1"
127.0.0.1:6379> incrbyfloat float 0.2
"1.2"
127.0.0.1:6379> get float
"1.2"
decr key
:将 key 中储存的数字值减一。
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
127.0.0.1:6379> get number
"134"
127.0.0.1:6379> decr number
(integer) 133
decrby key decrement
:将 key 所储存的值减去减量 decrement 。
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECRBY 操作。
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
127.0.0.1:6379> get number
"133"
127.0.0.1:6379> decrby number 10
(integer) 123
redis中是面向字节的,一个字节一个索引,而位是面向二进制的,所以一个bit一个索引,说明吐如下
setbit
key offset value:设置或清除指定偏移量上的位(bit),value只能为0或者1
getbit
key offset:获取offset上的值
bitcount
key [start end]:在字节索引start和end间查看1的个数
127.0.0.1:6379> setbit bitdemo 2 1
(integer) 0
127.0.0.1:6379> setbit bitdemo 10 1
(integer) 0
127.0.0.1:6379> getbit bitdemo 2
(integer) 1
127.0.0.1:6379> getbit bitdemo 10
(integer) 1
127.0.0.1:6379> bitcount bitdemo 0 0
(integer) 1
127.0.0.1:6379> bitcount bitdemo 0 1
(integer) 2
bitop
operation destkey key [key …]:对多个位数组进行按位与、或、异或运算,
operation可以是and、or、not、xor这四种操作中的任意一种。
bitop
and destkey key [key …] ,对一个或多个key求逻辑并,并将结果保存到destkey
bitop
or destkey key [key …] ,对一个或多个key求逻辑或,并将结果保存到destkey
bitop
xor destkey key [key …] ,对一个或多个key求逻辑异或,并将结果保存到destkey
bitop
not destkey key ,对给定key求逻辑非,并将结果保存到destkey
String是Redis最基本的数据类型,Redis是用c语言开发的。但是Redis中的字符串和c语言中的字符串类型却是有明显的区别。
String类型的数据结构存储方式有三种int、raw、embstr。那么这三种存储方式有什么区别呢?
Redis中规定假如存储的是「整数型值」,比如set num 1这样的类型,就会使用 int的存储方式进行存储,在redisObject的「ptr属性」中就会指向该值。
127.0.0.1:6379> set number 1
OK
127.0.0.1:6379> object encoding number
"int"
redisObject 是 Redis 类型系统的核心, 数据库中的每个键、值, 以及 Redis 本身处理的参数, 都表示为这种数据类型
假如存储的「字符串是一个字符串值并且长度大于32个字节」就会使用SDS(simple dynamic string)方式进行存储,并且encoding设置为raw;若是「字符串长度小于等于32个字节」就会将encoding改为embstr来保存字符串。
SDS 类似于 Java 中的 ArrayList,可以通过预分配冗余空间的方式来减少内存的频繁分配。
127.0.0.1:6379> set demo aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
OK
127.0.0.1:6379> object encoding demo
"embstr"
127.0.0.1:6379> APPEND demo b
(integer) 32
127.0.0.1:6379> object encoding demo
"raw"
SDS称为「简单动态字符串」,对于SDS中的定义在Redis的源码中有的三个属性int len、int free、char buf[]。
len保存了字符串的长度,free表示buf数组中未使用的字节数量,buf数组则是保存字符串的每一个字符元素。
如果没有1GB的内存限制,我们可以使用排序和Set完成这个算法:
① 首先将40亿个QQ号进行排序;
② 从小到大遍历,跳过重复元素只取第一个元素。将40亿个QQ号统统放进Set集合中,自动完成去重,Perfect
对40亿个QQ号进行排序需要多少时间?这个存储了40亿QQ号的数组容量已经超过1GB了,同理Set集合存储这么多的QQ号也导致内存超限了。
这时我们可以使用BitMap来去重
一个字节可以记录8个数是否存在(类似于计数排序),将QQ号对应的offset的值设置为1表示此数存在,遍历完40亿个QQ号后直接统计BITMAP上值为1的offset即可完成QQ号的去重。
天数为key,用户唯一标识为offset。
如下求2022.04.26和2022.04.27这2天的用户活跃数,22和34是用户的唯一标识
2022.04.26号,22和34号用户都登陆了,但是2022.04.27号只有22登陆了。
127.0.0.1:6379> setbit 20220426 22 1
(integer) 0
127.0.0.1:6379> setbit 20220426 34 1
(integer) 0
127.0.0.1:6379> setbit 20220427 22 1
(integer) 0
127.0.0.1:6379> bitop or 20220426demo 20220426 20220427
(integer) 5
127.0.0.1:6379> bitcount 20220426demo 0 -1
(integer) 2
clyu是用户名,offset是天数。
127.0.0.1:6379> setbit clyu 0 1
(integer) 0
127.0.0.1:6379> bitcount clyu 0 -1
(integer) 1