Redis里怎么快速搞定数值的加减,递增递减那些事儿分享下
- 问答
- 2025-12-30 18:55:24
- 3
说到在Redis里处理数字的加减、递增递减这些操作,这可以说是Redis最顺手、最高效的功能之一了,它不像关系型数据库,改个数字还得先查出来,在程序里计算,再写回去,搞不好还有并发问题,Redis直接用几个简单的命令就能原子性地搞定,又快又安全,下面我就把这些事儿给你捋一捋。
核心命令:INCR、DECR、INCRBY、DECRBY
最基本的操作就是给一个键的值加1或者减1,这用的就是INCR和DECR命令。(来源:Redis官方文档对INCR命令的描述)
你有一个键叫 page_views,用来记录网站浏览量,每次有人访问,你都不用先去读这个值是多少,直接发一条命令:
INCR page_views
Redis收到这个命令后,会做三件事:
- 看一下
page_views这个键存不存在,如果不存在,就当它的值是0。 - 在这个值的基础上加1。
- 把加1后的新值返回给你。
整个过程是一个原子操作,也就是说,就算有成千上万个客户端同时发送 INCR page_views 命令,Redis也会确保每个加1操作都一步步完成,绝对不会出现两个客户端读到同一个值然后加1,导致最终计数变少的情况,这就是它厉害的地方。
减1也一样,用 DECR 命令:
DECR items_in_stock
比如库存数量,卖出一件商品就减1。
那如果我想加或减的不是1,而是一个指定的数呢?比如给用户积分一次加10分,或者商品库存一次入库100件,这时候就用 INCRBY 和 DECRBY 命令。(来源:Redis官方文档对INCRBY命令的描述)
INCRBY 是增加一个整数:
INCRBY user:1000:score 10
这条命令的意思是把键 user:1000:score 的值增加10。
DECRBY 是减少一个整数:

DECRBY inventory:item001 5
这条命令是把库存减少5。
处理浮点数:INCRBYFLOAT
上面那几个命令都是针对整数的,但现实世界里,我们经常要处理小数,比如账户余额、温度值、权重等等,Redis也为这种情况准备了命令,叫 INCRBYFLOAT。(来源:Redis官方文档对INCRBYFLOAT命令的描述)
它的用法和 INCRBY 很像,但是后面跟的数可以是小数:
INCRBYFLOAT account:alice:balance 50.5 // 充值50.5元
INCRBYFLOAT account:alice:balance -20.1 // 消费20.1元
这个命令非常灵活,既可以加正数,也可以加负数(相当于减)。
这些操作为什么这么快?
你可能会想,这些操作这么快,是不是有什么魔法?其实道理很简单。(来源:基于对Redis内部实现机制的普遍理解)

- 单线程模型:Redis是单线程处理命令的,这意味着在任何一瞬间,都只有一个命令在被执行,所以
INCR这类命令根本不用考虑复杂的锁机制,因为不会被打断,天然就是线程安全的。 - 纯内存操作:数据都在内存里,读写速度极快,不像硬盘数据库那样有沉重的I/O开销。
- 简单高效的数据结构:对于整数,Redis在内部会尝试把它存成一个叫“整数集合”的紧凑结构,进行算术运算的效率非常高。
实战中用起来是什么样子?
光说命令可能有点干,我们想象几个实际场景:
-
限流器 你想限制一个API接口每分钟只能被一个用户调用60次,你可以这样做:
- 键名设计为
rate_limit:user_id:202405201330(用户ID + 年月日时分)。 - 每次用户调用接口时,执行
INCR rate_limit:user_id:202405201330。 - 如果是第一次调用,这个键的值会变成1,同时你可以用
EXPIRE命令给这个键设置60秒的过期时间。 - 之后每次调用都
INCR一下,并检查返回值,如果超过60,就拒绝请求。 - 等到下一分钟,键名变了,又是新的开始,这个方法非常简洁高效。
- 键名设计为
-
商品库存扣减 秒杀场景下,库存扣减是典型的“判断+扣减”的原子性问题,用Redis可以这么搞:
- 商品库存初始化:
SET inventory:seckill_item 100 - 用户下单时,不用繁琐的事务,直接一条命令:
DECR inventory:seckill_item - 然后判断这个命令的返回值,如果返回值大于等于0,说明扣减成功,库存充足;如果返回-1,说明库存已经从0开始减了,扣减失败,库存不足。 这样就完美避免了超卖问题。
- 商品库存初始化:
-
实时排行榜的分数更新 虽然更复杂的排行榜用
ZSET(有序集合)更强大,但如果是简单的积分榜,用INCRBY也能做。- 每个用户一个积分键:
INCRBY user:1000:score 5 - 要查排名的时候,可以用
GET命令取出所有用户的分数,然后在应用层做个排序,对于用户量不是特别巨大的情况,完全够用。
- 每个用户一个积分键:
需要注意的几个小地方
虽然这些命令很好用,但也有几点要留意:
- 类型要对:你只能对数字类型的值进行这些操作,如果你对一个存着字符串"hello"的键执行
INCR,Redis会报错。 - 精度问题:
INCRBYFLOAT处理的是浮点数,在计算机中浮点数计算可能存在微小的精度损失,这在所有编程语言和系统中都是普遍现象,所以如果是要求精确计算的金融场景,比如一分钱都不能差的账户,可能需要用整数来存(比如用分做单位),或者使用数据库的事务功能。 - 非唯一性:
INCR生成的序列是唯一的、递增的,但它不是严格连续的,如果你有多个Redis实例(集群),每个实例自己生成ID,或者你删掉了一个键,再重新INCR,中间就会有间隔,如果需要绝对连续,得想别的办法。
Redis提供的这一套递增递减命令,就像是给你了一套顺手的小工具,对于计数器、限流、实时统计这类需要高频且原子性修改数值的场景,简直是量身定做,关键是理解它们的原子特性和适用场景,然后就能在项目里灵活运用,大大提升性能和开发效率。
本文由盘雅霜于2025-12-30发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/71432.html
