文章目录
Redis之String命令
注:本文是基于Linux系统上Redis v5.0.7进行讲解
1.incr
Redis Incr 命令将 key 中储存的数字值增一;
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作;
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误;
本操作的值限制在 64 位(bit)有符号数字表示之内;
命令的返回值是key的新值



2.setnx
指定的 key 不存在时,为 key 设置指定的值,命令返回1;
指定的 key 存在时,不会覆盖值,命令返回0;
SETNX KEY_NAME VALUE

对于set来说,是会进行值覆盖的

3.getrange
用于获取存储在指定 key 中字符串的子字符串;
字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内);
命令返回子字符串;
当key不存在时,返回空字符串
GETRANGE KEY_NAME start end




4.mset
命令用于同时设置一个或多个 key-value 对;
如果 key 已经存在, mset 命令将会替换旧的值;
指定的 key不存在时,为 key 设置指定的值;
命令返回"OK"
MSET key1 value1 key2 value2 .. keyN valueN


5.setex
命令为指定的 key 设置值及其过期时间,单位是秒
如果 key已经存在,SETEX 命令将会替换旧的值;
指定的 key不存在时,为 key 设置指定的值;
命令返回"OK"
SETEX KEY_NAME TIMEOUT VALUE

6.setbit
setbit吧,大家知道位操作,只有两个值,0和1,8个位正好是1b,所以位操作是非常节省空间的一种操作;
1 Byte(B) = 8 bit
1 Kilo Byte(KB) = 1024B
1 Mega Byte(MB) = 1024 KB
1 Giga Byte (GB)= 1024 MB
命令用于对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit);
返回指定偏移量原来储存的位.
时间复杂度: O(1)
offset 参数必须大于或等于 ,小于 2^32 (bit 映射被限制在 512 MB 之内)。
2^9*2^20*2^3=2^32
Setbit KEY_NAME OFFSET 0/1

1)5的二进制位是101,以下实验说明不是在101上进行操作

2)以下对二进制get一下,发现输出的全都是\x00
x这是一个转义符,\xhh表示二位十六进制,在这里
\x00 == 0x00
\x77 == 0x77
0x00转换为10进制后是0,ascii字符的NULL
0x77转换为10进制后是119+,对应于ascii字符的w
说明不能用get


3)以下实验说明第一次设置key时,不能不指定0或者1,甚至对原有bitkey设置时也不可以

4)以下实验说明如果偏移量过大的话,会扩大值,并且原来的偏移量的值不会变

7.getbit
命令用于对 key 所储存的字符串值,获取字符串指定偏移量上的位(bit);
当偏移量 OFFSET 比字符串值的长度大,或者 key 不存在时,返回 0
时间复杂度: O(1)
GETBIT KEY_NAME OFFSET

8.bitop
时间复杂度: O(N)
对一个或多个保存二进制位的字符串key进行位元操作,并将结果保存到destkey上;
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
除了NOT操作外,其他操作都可以接受一个或多个key作为输入;
当BITOP处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看做0;
空的key也被看作是包含0的字符串序列;
返回值:保存到 的字符串的长度,和输入 中最长的字符串长度相等
当处理大型矩阵(matrix)或者进行大数据量的统计时,最好将任务指派到附属节点(slave)进行,避免阻塞主节点。
1)and运算:
key1的值为"foobar" 对应的二进制为 1100110 1101111 1101111 1100010 1100001 1110010
key2的值为"abcdef" 对应的二进制为 1100001 1100010 1100011 1100100 1100101 1100110
BITOP AND dest key1 key2 的意思是 BITOP 是命令 AND 并运算,并运算的结果存储在dest里面

2)or

9.setbit应用
场景: 1亿个用户,每个用户登陆/做任意操作,记为 今天活跃,否则记为不活跃;
每周评出: 有奖活跃用户: 连续7天活动
每月评,等等…
其实简单说就是统计一下连续7天(或者连续30天)有多少人连续登陆过
咱们先来想一想传统的方案
很容易就会想到只要用户登陆了,我在表中插入一条数据,并且记录上对应的日期,然后用mysql里面的记录来逐个判断,类似于这样:
但这样是存在一些问题的,主要的问题在于用户量高达1亿,每个用户登陆一次就远远的超过mysql的极限了,更不要说统计一星期了,而且用上group ,sum运算,计算也是非常慢的

先分析一下思路,对于某一天来说,我们可以把这一天想像成一根小木棍,分成了不同的段落,每个段落对应的就是用户的位(因为有user_id),默认值都是0,只要有人登陆了,就把对应的用户的位置标为1即可;
如下图所示,这个就是一天的登陆情况,user_id为6和user_id为8的用户登陆过。其余的都为没有登陆过。因为这个是位操作,所以占的空间很小,1亿的用户,所占的空间也就不到12M。
一天的问题咱们解决了,如何解决他们是否连续登陆过呢?

我们可以用上多个"木棍",我们可以把每一天作为一个键,然后每天对用户登陆状态进行标记,在最后用每天做一个"与运算"就可以准确的知道哪些用户连续登陆了;
如下例,优点为:
1、节约空间, 1亿人每天的登陆情况,用1亿bit,约1200WByte,约10M 的字符就能表示;
2、计算方便


1亿个用户一天的数据量也就 1 0000 0000bit = 11.92m,也就是说用户一天的登录信息也就产生11.92m的数据量。一个月也就357.63m的数据量;
具体实现过程(为了实验方便,我们就假设4个用户0,1,2,3,统计两天的登录量):
mon: 1010 (用户0未登录,用户1登录,用户2未登录,用户3登录)
tue: 1101 (用户0登录,用户1未登录,用户2登录,用户3登录)

可以看到mon 和 tue做and运算,得到结果result 为 :1000,则表示用户3连续两天都登陆,其他用户两天中只有一天登录
10.decr
命令将 key 中储存的数字值减一;
命令的返回值是key的新值;
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作,即把值设为-1;
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误;
本操作的值限制在 64 位(bit)有符号数字表示之内;
DECR KEY_NAME


11.decrby
命令将 key 所储存的值减去指定的减量值;
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误;
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECRBY 操作;
本操作的值限制在 64 位(bit)有符号数字表示之内;
返回key的新值
DECRBY KEY_NAME DECREMENT_AMOUNT


12.strlen
命令用于获取指定 key 所储存的字符串值的长度;
当 key 储存的不是字符串值时,返回一个错误;
命令返回字符串值的长度;
当 key 不存在时,返回 0
STRLEN KEY_NAME

14.msetnx
命令用于所有给定 key 都不存在时,同时设置一个或多个 key-value 对;
当所有 key 都成功设置,返回 1 ;如果所有给定 key 都设置失败(至少有一个 key 已经存在),那么返回 0
MSETNX key1 value1 key2 value2 .. keyN valueN
成功时

失败时


15.mget
令返回所有(一个或多个)给定 key 的值;
如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil;
命令返回一个包含所有给定 key 的值的列表
MGET KEY1 KEY2 .. KEYN

16.incrby
命令将 key 中储存的数字加上指定的增量值;
如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误;
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令;
本操作的值限制在 64 位(bit)有符号数字表示之内
INCRBY KEY_NAME INCR_AMOUNT



17.incrbyfloat
命令为 key 中所储存的值加上指定的浮点数增量值;
如果 key 不存在,那么 INCRBYFLOAT 会先将 key 的值设为 0 ,再执行加法操作;
执行命令之后 key 的值
INCRBYFLOAT KEY_NAME INCR_AMOUNT
1)值和增量都不是指数符号时

2)值和增量都是指数符号;
用 SET 设置的值可以是指数符号,但执行 INCRBYFLOAT 之后格式会被改成非指数符号

3)可以对整数类型执行

4)后跟的 0 会被移除;
SET 设置的值小数部分可以是 0;
但 INCRBYFLOAT 会将无用的 0 忽略掉,有需要的话,将浮点变为整数

18.setrange
用指定的字符串覆盖给定 key 所储存的字符串值,覆盖的位置从偏移量 offset 开始
命令返回被修改后的字符串长度
SETRANGE KEY_NAME OFFSET VALUE

19.psetex
命令以毫秒为单位设置 key 的生存时间(1毫秒==0.001秒)
设置成功时返回 OK
PSETEX key1 EXPIRY_IN_MILLISECONDS value1

20.append
命令用于为指定的 key 追加值;
如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾;
如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样;
返回的是追加指定值之后, key 对应的新字符串的长度
APPEND KEY_NAME NEW_VALUE
21.getset
命令用于设置指定 key 的值,并返回 key 旧的值;
当 key 没有旧值时,即 key 不存在时,返回 nil ,并为这个key设置值;
当 key 存在但不是字符串类型时,返回一个错误。
GETSET KEY_NAME VALUE
22.bitcount
BITCOUNT key [start] [end]
时间复杂度: O(N)
计算给定字符串中,被设置为 1 的比特位的数量。
一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。
start 和 end 参数的设置和 GETRANGE key start end 命令类似,都可以使用负数值: 比如 -1 表示最后一个字节, -2 表示倒数第二个字节,以此类推。
不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。
返回值:被设置为 1 的位的数量。
模式:使用 bitmap 实现用户上线次数统计
Bitmap 对于一些特定类型的计算非常有效。
假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户 A 上线了多少天,用户 B 上线了多少天,诸如此类,以此作为数据,从而决定让哪些用户参加 beta 测试等活动 —— 这个模式可以使用 SETBIT key offset value 和 BITCOUNT key [start] [end] 来实现。
比如说,每当用户在某一天上线的时候,我们就使用 SETBIT key offset value ,以用户名作为 key ,将那天所代表的网站的上线日作为 offset 参数,并将这个 offset 上的为设置为 1 。
举个例子,如果今天是网站上线的第 100 天,而用户 peter 在今天阅览过网站,那么执行命令 SETBIT peter 100 1 ;如果明天 peter 也继续阅览网站,那么执行命令 SETBIT peter 101 1 ,以此类推。
当要计算 peter 总共以来的上线次数时,就使用 BITCOUNT key [start] [end] 命令:执行 BITCOUNT peter ,得出的结果就是 peter 上线的总天数。
性能
前面的上线次数统计例子,即使运行 10 年,占用的空间也只是每个用户 10*365 比特位(bit),也即是每个用户 456 字节。对于这种大小的数据来说, BITCOUNT key [start] [end] 的处理速度就像 GET key 和 INCR key 这种 O(1) 复杂度的操作一样快。
如果你的 bitmap 数据非常大,那么可以考虑使用以下两种方法:
1.将一个大的 bitmap 分散到不同的 key 中,作为小的 bitmap 来处理。使用 Lua 脚本可以很方便地完成这一工作。
使用 BITCOUNT key [start] [end] 的 start 和 end 参数,每次只对所需的部分位进行计算,将位的累积工作(accumulating)放到客户端进行,并且对结果进行缓存 (caching)。


23.bitpos
返回位图中第一个值为1的二进制位的位置。
在默认情况下, 命令将检测整个位图, 但用户也可以通过可选的 参数和 参数指定要检测的范围。
BITPOS key bit [start] [end]

24.bitfield
时间复杂度: 每个子命令的复杂度为 O(1) 。
BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]