【Redis】6.计数其他命令

发布时间:2026/7/23 9:09:24
【Redis】6.计数其他命令 文章目录2. Redis 常见数据类型2.2 String 字符串2.2.2 计数命令2.2.2.1 INCR针对value12.2.2.2 INCRBY针对valuen2.2.2.3 DECR针对value-12.2.2.4 DECYBY针对value-n2.2.2.5 INCRBYFLOAT针对value/-小数2.2.3 其他命令2.2.3.1 APPEND追加子串2.2.3.2 GETRANGE返回范围子串2.2.3.3 SETRANGE覆盖范围子串2.2.3.4 STRLEN获取子串长度2.2.4 命令小结2.2.5 内部编码2.2.6 典型使用场景2.2.6.1 缓存Cache功能2.2.6.2 计数Counter功能2.2.6.3 共享会话Session2.2.6.4 手机验证码2. Redis 常见数据类型2.2 String 字符串2.2.2 计数命令2.2.2.1 INCR针对value1将key对应的string表示的数字加一。如果key不存在则视为key对应的value是0。如果key对应的string不是一个整型或者范围超过了64位有符号整型则报错。语法INCR key命令有效版本1.0.0之后时间复杂度O(1)返回值integer类型的加完后的数值。64位/8字节表示的整数相当于C中的long longJava中的long示例127.0.0.1:6379 EXISTS mykey (integer) 1 127.0.0.1:6379 INCR mykey (error) ERR value is not an integer or out of range 127.0.0.1:6379 SET mykey 10 OK 127.0.0.1:6379 INCR mykey (integer) 11 127.0.0.1:6379 SET mykey 46756767986967967977987987 OK 127.0.0.1:6379 INCR mykey (error) ERR value is not an integer or out of range # 当前值不是整数或者超过了范围 127.0.0.1:6379 SET mykey not a number OK 127.0.0.1:6379 INCR mykey (error) ERR value is not an integer or out of range 127.0.0.1:6379 del mykey (integer) 0 127.0.0.1:6379 INCR mykey # incr操作的key如果不存在。就会把这个key的value当作0来使用 (integer) 1 127.0.0.1:63792.2.2.2 INCRBY针对valuen将key对应的string表示的数字加上对应的值。可以加上一个负数也就是减。如果key不存在则视为key对应的value是0。如果key对应的string不是一个整型或者范围超过了64位有符号整型则报错。语法INCRBY key decrement命令有效版本1.0.0之后时间复杂度O(1)返回值integer类型的加完后的数值。示例127.0.0.1:6379 del mykey (integer) 1 127.0.0.1:6379 EXISTS mykey (integer) 0 127.0.0.1:6379 INCRBY mykey 3 (integer) 3 127.0.0.1:6379 SET mykey 10 OK 127.0.0.1:6379 INCRBY mykey 3 (integer) 13 127.0.0.1:6379 INCRBY mykey not a number # 加上不是整数的 (error) ERR value is not an integer or out of range 127.0.0.1:6379 INCRBY mykey 3 (integer) 16 127.0.0.1:6379 SET mykey 234293482390480948029348230948 OK 127.0.0.1:6379 INCRBY mykey 3 (error) ERR value is not an integer or out of range 127.0.0.1:6379 SET mykey not a number OK 127.0.0.1:6379 INCRBY mykey 3 (error) ERR value is not an integer or out of range 127.0.0.1:6379 SET mykey 10 OK 127.0.0.1:6379 INCRBY mykey -1 # 加上一个负数 (integer) 9 127.0.0.1:6379事实上虽然incrby可以实现下面的减但是可能不够人性化别人可能会觉得如果可以减那干嘛取名加呢所以虽然可以实现减但是还是分开来设计了这几个命令。2.2.2.3 DECR针对value-1将key对应的string表示的数字减一。如果key不存在则视为key对应的value是0。如果key对应的string不是一个整型或者范围超过了64位有符号整型则报错。语法DECR key命令有效版本1.0.0之后时间复杂度O(1)返回值integer类型的减完后的数值。示例127.0.0.1:6379 del mykey (integer) 1 127.0.0.1:6379 exists mykey (integer) 0 127.0.0.1:6379 DECR mykey (integer) -1 127.0.0.1:6379 SET mykey 10 OK 127.0.0.1:6379 DECR mykey (integer) 9 127.0.0.1:6379 SET mykey 767678678678564545454586867868678678 OK 127.0.0.1:6379 DECR mykey (error) ERR value is not an integer or out of range 127.0.0.1:6379 SET mykey not a number OK 127.0.0.1:6379 DECR mykey (error) ERR value is not an integer or out of range 127.0.0.1:63792.2.2.4 DECYBY针对value-n将key对应的string表示的数字减去对应的值。如果key不存在则视为key对应的value是0。如果key对应的string不是一个整型或者范围超过了64位有符号整型则报错。语法DECRBY key decrement命令有效版本1.0.0之后时间复杂度O(1)返回值integer类型的减完后的数值。示例127.0.0.1:6379 del mykey (integer) 1 127.0.0.1:6379 exists mykey (integer) 0 127.0.0.1:6379 DECRBY mykey 3 (integer) -3 127.0.0.1:6379 SET mykey 10 OK 127.0.0.1:6379 DECRBY mykey 3 (integer) 7 127.0.0.1:6379 DECRBY mykey not a number (error) ERR value is not an integer or out of range 127.0.0.1:6379 DECRBY mykey 3 (integer) 4 127.0.0.1:6379 SET mykey 76879879879879878798676767676798 OK 127.0.0.1:6379 DECRBY mykey 3 (error) ERR value is not an integer or out of range 127.0.0.1:6379 SET mykey not a number OK 127.0.0.1:6379 DECRBY mykey 3 (error) ERR value is not an integer or out of range 127.0.0.1:63792.2.2.5 INCRBYFLOAT针对value/-小数将key对应的string表示的浮点数加上对应的值。如果对应的值是负数则视为减去对应的值。如果key不存在则视为key对应的value是0。如果key对应的不是string或者不是一个浮点数则报错。允许采用科学计数法表示浮点数。语法INCRBYFLOAT key increment命令有效版本2.6.0之后时间复杂度O(1)返回值加/减完后的数值。示例127.0.0.1:6379 del mykey (integer) 1 127.0.0.1:6379 exists mykey (integer) 0 127.0.0.1:6379 INCRBYFLOAT mykey 0.1 0.1 127.0.0.1:6379 SET mykey 10.50 OK 127.0.0.1:6379 INCRBYFLOAT mykey 0.1 10.6 127.0.0.1:6379 INCRBYFLOAT mykey -5 5.6 127.0.0.1:6379 SET mykey 5.0e3 OK 127.0.0.1:6379 INCRBYFLOAT mykey 2.0e2 5200 127.0.0.1:6379 SET mykey 10.50 OK 127.0.0.1:6379 INCRBYFLOAT mykey -50 -39.5 127.0.0.1:6379很多存储系统和编程语言内部使用CAS机制实现计数功能会有一定的CPU开销但在Redis中完全不存在这个问题因为Redis是单线程架构任何命令到了Redis服务端都要顺序执行。2.2.3 其他命令2.2.3.1 APPEND追加子串如果key已经存在并且是一个string命令会将value追加到原有string的后边。如果key不存在则效果等同于SET命令。append返回值长度的单位是字节。redis的字符串不会对字符编码做任何处理。(redis不认识字符只认识字节)当前使用的XShell终端默认的字符编码是utf8。在终端中输入汉字之后也就是按照utf8编码的。一个汉字在utf8字符集中通常是3个字节的。语法APPEND KEY VALUE命令有效版本2.0.0之后时间复杂度O(1)。追加的字符串一般长度较短, 可以视为O(1)返回值追加完成之后string的长度。示例127.0.0.1:6379 exists mykey (integer) 0 127.0.0.1:6379 APPEND mykey Hello (integer) 5 127.0.0.1:6379 get mykey Hello 127.0.0.1:6379 APPEND mykey world (integer) 10 127.0.0.1:6379 get mykey Helloworld 127.0.0.1:6379 APPEND mykey hahaha (integer) 17 127.0.0.1:6379 get mykey Helloworld hahaha 127.0.0.1:6379 APPEND mykey 哇 # XShell中汉字utf8编码通常3字节 (integer) 20 127.0.0.1:6379 get mykey Helloworld hahaha\xe5\x93\x87 127.0.0.1:6379在启动redis客户端的时候加上一个--raw这样的选项。就可以使redis客户端能够自动的把二进制数据尝试翻译。127.0.0.1:6379 quit rootyudukai:~# redis-cli --raw 127.0.0.1:6379 keys * mykey 127.0.0.1:6379 get mykey Helloworld hahaha哇 127.0.0.1:6379操作linux的时候,千万注意,不要乱按ctrlsctrls在xshell中的作用是“冻结当前画面”。ctrlq解除冻结。2.2.3.2 GETRANGE返回范围子串返回key对应的string的子串由start和end确定左闭右闭。可以使用负数表示倒数。-1代表倒数第一个字符-2代表倒数第二个其他的与此类似。可以认为是len-1个元素超过范围的偏移量会根据string的长度调整成正确的值。如果字符串保存的是汉字这个时候随便指的是一个汉字3个字节但是你给他切开来了进行字串切分可能切出来的不是正常的汉字。redis中指定的区间是闭区间。但是C和Java中大部分的区间都是前闭后开。语法GETRANGE key start end命令有效版本2.4.0之后时间复杂度O(N)。N为[start, end]区间的长度。由于string通常比较短, 可以视为是O(1)返回值string类型的子串示例127.0.0.1:6379 SET mykey This is a string OK 127.0.0.1:6379 GETRANGE mykey 0 3 This 127.0.0.1:6379 GETRANGE mykey -3 -1 ing 127.0.0.1:6379 GETRANGE mykey 0 -1 # 从0号元素最开始元素到-1号元素最后元素 This is a string 127.0.0.1:6379 GETRANGE mykey 10 100 string 127.0.0.1:63792.2.3.3 SETRANGE覆盖范围子串覆盖字符串的一部分从指定的偏移开始。语法SETRANGE key offset value命令有效版本2.2.0之后时间复杂度O(N),N为value的长度。由于一般给的value比较短, 通常视为O(1)。返回值替换后的string的长度。示例127.0.0.1:6379 SET key1 Hello World OK 127.0.0.1:6379 SETRANGE key1 6 Redis (integer) 11 127.0.0.1:6379 get key1 Hello Redis 127.0.0.1:6379 setrange key1 1 a (integer) 11 127.0.0.1:6379 get key1 Hallo Redis 127.0.0.1:6379 setrange key1 10 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (integer) 57 127.0.0.1:6379 get key1 Hallo Rediaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 127.0.0.1:6379 setrange key2 1 aaa # 对不存在的key进行setrange操作 (integer) 4 127.0.0.1:6379 get key2 \x00aaa # \x00其实就是凭空生成了一个字节这个字节内的内容就是0x00,aaa就被追加到这个0x00的后面了 127.0.0.1:63792.2.3.4 STRLEN获取子串长度获取key对应的string的长度。单位是字节C中字符串的长度本身是用字节为单位的Java中的char基于unicode这样的编码方式就能够表示中文等符号一个char是2字节string使用utf8一个汉字3字节MySQL的时候varchar(N)此处N的单位就是字符也是完整的汉字这样的一个字符也可能是多个字节当key存放的类似不是string时报错。语法STRLEN key命令有效版本2.2.0之后时间复杂度O(1)返回值string的长度。或者当key不存在时返回0。示例127.0.0.1:6379 exists mykey (integer) 0 127.0.0.1:6379 SET mykey Hello world OK 127.0.0.1:6379 strlen mykey (integer) 11 127.0.0.1:6379 strlen nonexisting (integer) 0 127.0.0.1:63792.2.4 命令小结下表是字符串类型命令的效果、时间复杂度开发人员可以参考此表结合自身业务需求和数据大小选择合适的命令。字符串类型命令小结O(k)可以当作O(1)因为这里的k是自己输入的个数我们也不可能输入太多个。2.2.5 内部编码字符串类型的内部编码有3种int8个字节的长整型。embstr小于等于39个字节的字符串。适用于比较短的字符串。raw大于39个字节的字符串。在Redis 3.0及之后的版本中判断字符串使用embstr还是raw的临界值是 44 字节Redis会根据当前值的类型和长度动态决定使用哪种内部编码实现。整型类型示例如下127.0.0.1:6379 set key 666 OK 127.0.0.1:6379 object encoding key int 127.0.0.1:6379短字符串示例如下127.0.0.1:6379 set key1 hello OK 127.0.0.1:6379 object encoding key1 embstr 127.0.0.1:6379 set key8 1.5 # redis存储小数本质上还是把小数当作字符串来存储。与整数相比差别比较大了整数直接使用int来存储比较方便算数运算小数用字符串存储每次计算需要先转换成小数计算然后计算结果转换成zifx OK 127.0.0.1:6379 object encoding key8 embstr 127.0.0.1:6379长字符串示例如下127.0.0.1:6379 set key2 one string greater than 39 bytes ........ OK 127.0.0.1:6379 object encoding key2 embstr 127.0.0.1:6379 set key3 one string greater than 39 bytes ......................................................... OK 127.0.0.1:6379 object encoding key3 raw 127.0.0.1:6379 set key4 one string greater than 39 bytes ......... # 刚好42字符 OK 127.0.0.1:6379 object encoding key4 embstr 127.0.0.1:6379 set key5 one string greater than 39 bytes .......... # 刚好43字符 OK 127.0.0.1:6379 object encoding key5 embstr 127.0.0.1:6379 set key6 one string greater than 39 bytes ........... # 刚好44字符 OK 127.0.0.1:6379 object encoding key6 embstr 127.0.0.1:6379 set key7 one string greater than 39 bytes ............ # 刚好45字符 OK 127.0.0.1:6379 object encoding key7 raw 127.0.0.1:63792.2.6 典型使用场景2.2.6.1 缓存Cache功能下图是比较典型的缓存使用场景其中Redis作为缓冲层MySQL作为存储层绝大部分请求的数据都是从Redis中获取。由于Redis具有支撑高并发的特性所以缓存通常能起到加速读写和降低后端压力的作用。Redis MySQL组成的缓存存储架构图下面的伪代码模拟了上图的业务数据访问过程假设业务是根据用户uid获取用户信息UserInfogetUserInfo(longuid){...}首先从Redis获取用户信息我们假设用户信息保存在 “user:info:uid” 对应的键中// 根据 uid 得到 Redis 的键String keyuser:info:uid;// 尝试从 Redis 中获取对应的值String valueRedis 执行命令get key;// 如果缓存命中hitif(value!null){// 假设我们的用户信息按照 JSON 格式存储UserInfo userInfoJSON 反序列化(value);returnuserInfo;}如果没有从Redis中得到用户信息及缓存miss则进一步从MySQL中获取对应的信息随后写入缓存并返回// 如果缓存未命中missif(valuenull){// 从数据库中根据 uid 获取用户信息UserInfo userInfoMySQL 执行 SQLselect*from user_info where uiduid// 如果表中没有 uid 对应的用户信息if(userInfonull){响应404returnnull;}// 将用户信息序列化成 JSON 格式String valueJSON 序列化(userInfo);// 写入缓存为了防止数据腐烂rot设置过期时间为 1 小时3600 秒Redis 执行命令set key value ex3600// 返回用户信息returnuserInfo;}通过增加缓存功能在理想情况下每个用户信息一个小时期间只会有一次MySQL查询极大地提升了查询效率也降低了MySQL的访问数。上述描述的过程相当于是把最近使用到的数据作为热点数据。(暗含了一层假设某个数据一旦被用到了那么很可能在最近这段时间就会被反复用到)不过上述策略存在一个明显的问题随着时间的推移肯定是会有越来越多的key在redis上访问不到从而从mysql读取并写入redis了此时redis中的数据不是就越来越多嘛在把数据写给redis的同时给这个key设置一个过期时间Redis也在内存不足的时候提供了淘汰策略与MySQL等关系型数据库不同的是Redis没有表、字段这种命名空间而且也没有对键名有强制要求除了不能使用一些特殊字符。但设计合理的键名有利于防止键冲突和项目的可维护性比较推荐的方式是使用 “业务名:对象名:唯一标识:属性” 作为键名。例如MySQL的数据库名为vs用户表名为user_info那么对应的键可以使用 “vs:user_info:6379”、“vs:user_info:6379:name” 来表示如果当前Redis只会被一个业务使用可以省略业务名 “vs:”。如果键名过长则可以使用团队内部都认同的缩写替代例如 “user:6379:friends:messages:5217” 可以被 “u:6379:fr:m:5217” 代替。毕竟键名过长还是会导致Redis的性能明显下降的。2.2.6.2 计数Counter功能许多应用都会使用Redis作为计数的基础工具它可以实现快速计数、查询缓存的功能同时数据可以异步处理或者落地到其他数据源。如下图所示例如视频网站的视频播放次数可以使用Redis来完成用户每播放一次视频相应的视频播放数就会自增1。记录视频播放次数// 在 Redis 中统计某视频的播放次数longincrVideoCounter(longvid){keyvideo:vid;longcountRedis 执行命令incr keyreturncounter;}实际中要开发一个成熟、稳定的真实计数系统要面临的挑战远不止如此简单防作弊、按照不同维度计数、避免单点问题、数据持久化到底层数据源等。2.2.6.3 共享会话Session如下图所示一个分布式Web服务将用户的Session信息例如用户登录信息保存在各自的服务器中。但这样会造成一个问题出于负载均衡的考虑分布式服务会将用户的访问请求均衡到不同的服务器上并且通常无法保证用户每次请求都会被均衡到同一台服务器上这样当用户刷新一次访问是可能会发现需要重新登录这个问题是用户无法容忍的。Session分散存储为了解决这个问题可以使用Redis将用户的Session信息进行集中管理如下图所示。在这种模式下只要保证Redis是高可用和可扩展性的无论用户被均衡到哪台Web服务器上都集中从Redis中查询、更新Session信息。Redis集中管理Session2.2.6.4 手机验证码很多应用出于安全考虑会在每次进行登录时让用户输入手机号并且配合给手机发送验证码然后让用户再次输入收到的验证码并进行验证从而确定是否是用户本人。为了短信接口不会频繁访问会限制用户每分钟获取验证码的频率例如一分钟不能超过5次如下图所示。短信验证码此功能可以用以下伪代码说明基本实现思路String 发送验证码(phoneNumber){keyshortMsg:limit:phoneNumber;// 设置过期时间为 1 分钟60 秒// 使用 NX只在不存在 key 时才能设置成功bool rRedis 执行命令set key1ex60nxif(rfalse){// 说明之前设置过该手机的验证码了longcRedis 执行命令incr keyif(c5){// 说明超过了一分钟 5 次的限制了// 限制发送returnnull;}}// 说明要么之前没有设置过手机的验证码要么次数没有超过 5 次String validationCode生成随机的6位数的验证码();validationKeyvalidation:phoneNumber;// 验证码 5 分钟300 秒内有效Redis 执行命令set validationKey validationCode ex300;// 返回验证码随后通过手机短信发送给用户returnvalidationCode;}// 验证用户输入的验证码是否正确bool 验证验证码(phoneNumber,validationCode){validationKeyvalidation:phoneNumber;String valueRedis 执行命令get validationKey;if(valuenull){// 说明没有这个手机的验证码记录验证失败returnfalse;}if(valuevalidationCode){returntrue;}else{returnfalse;}}以上介绍了使用Redis的字符串数据类型可以使用的几个场景但其适用场景远不止于此开发人员可以结合字符串类型的特点以及提供的命令充分发挥自己的想象力在自己的业务中去找到合适的场景去使用Redis的字符串类型。