用Redis搞定订单号生成,效率提升还能避免重复这些事儿
- 问答
- 2026-01-11 12:29:50
- 2
用户想了解如何用Redis生成订单号,直接要干货,不要术语,还得避免重复,那咱们就从一个实际场景说起。
想象一下,你正在运营一个电商平台,每逢“双十一”这样的促销日,每秒都可能产生成千上万的订单,如果用数据库的自增ID来生成订单号,数据库很容易成为瓶颈,压力巨大,搞不好整个系统就卡死了,单纯的自增ID信息量太少,看不出任何业务含义,这时候,Redis就能大显身手了,它处理速度极快,是解决这个问题的好帮手。
核心思路:利用Redis的原子性操作
Redis是单线程的,它的命令是逐个执行的,这意味着它的某些操作具有“原子性”,简单说,就是当一个命令在执行时,不会被其他命令打断,这样可以确保在高并发的情况下,也不会出现两个请求拿到同一个号码的情况,这是我们避免订单号重复的关键。
一种常见且实用的方案:日期 + 当日自增序号
这个方案生成的订单号看起来可能是这样的:2024061400000001,前面8位是日期(2024年6月14日),后面8位是这一天内从1开始连续自增的序列号,这样做有几个好处:
- 一眼看懂日期:从订单号就能知道是哪天的订单,方便查询和统计。
- 避免过长:相比使用时间戳,这种组合方式长度固定,更简洁。
- 基本无重复:只要同一秒内的订单数不超过序列号的容量(比如后面8位支持到1亿),就不会重复。
具体怎么做呢?我们需要用到一个关键的Redis命令:INCR,这个命令能将一个键的值增加1,并返回增加后的值,如果这个键不存在,Redis会先把它设置为0,再执行加1操作。
我们可以把订单的日期作为Redis的键。order:id:20240614,每天的订单都对应一个唯一的键。
生成订单号的步骤就变得非常简单:
- 获取当前日期,格式化为“YYYYMMDD”的形式,拼接到键中,
order:id:20240614。 - 向Redis发送命令
INCR order:id:20240614,Redis会保证这个操作是原子的,即使一万个请求同时过来,也会排着队一个一个地加1,绝对不会返回重复的值。 - Redis返回一个自增后的序号,
15。 - 我们将这个序号格式化为固定长度(比如用0补足到8位),变成
00000015。 - 把日期和格式化后的序号拼接起来,最终的订单号就是
2024061400000015。
应对极端情况:设置键的过期时间
你可能会问,这个 order:id:20240614 的键会一直留在Redis里吗?不会的,我们可以给它设置一个过期时间,既然它是当天的订单计数器,那么到第二天凌晨过期就最合适了,我们可以使用Redis的 EXPIRE 命令,在第一次创建这个键时(也就是执行INCR返回1的时候),同时设置它在当天晚上23点59分59秒过期,这样Redis会自动清理掉前几天的键,避免存储空间无限增长。
更进一步:加入更多信息和应对大并发
上面是最基础的版本,我们还可以根据需求进行优化:
- 增加业务标识和机器标识:在大型分布式系统中,可能有多台服务器同时在生成订单号,为了避免万一Redis集群出现分区问题(虽然概率极低)导致不同机器生成了重复ID,可以在订单号中加入机器编号或数据中心编号,
业务标识 + 机器号 + 日期 + 序号,这样即使有极端情况,也能通过机器号来区分。 - 解决“序列号重置”问题:如果应用在一天之内重启,上面的方法没问题,因为Redis里的计数器还在,但如果Redis本身宕机且数据丢失了,重启后序列号会从1重新开始,这就有可能和宕机前生成的订单号重复,为了解决这个问题,可以考虑更复杂的方案,一种方法是使用Redis的持久化机制(RDB或AOF)来保证数据不丢失,另一种方法是结合数据库:在应用启动时,去数据库查询一下当天已存在的最大订单号,然后用这个最大值来初始化Redis的计数器,查询到当天最大订单号是
2024061400000050,那么就可以执行SET order:id:20240614 50,这样后续的INCR操作就会从51开始了。
总结一下
用Redis生成订单号,核心就是利用其单线程原子操作的特性,确保在高并发下号码不重复。日期 + 当日自增序号 是一种简单高效的方案,通过 INCR 命令轻松实现,通过设置过期时间管理内存,通过增加业务前缀和机器标识来增强分布式环境下的可靠性,对于数据持久性要求极高的场景,则可以结合数据库来初始化计数器,避免重启导致的重复风险,这种方法不仅能轻松应对高并发流量,生成的订单号还兼具可读性,是一个非常实用的解决方案。

本文由称怜于2026-01-11发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/78685.html
