如何设计一个能扛住双11并发的订单号生成方案

2024-02-11 18:58

本文主要是介绍如何设计一个能扛住双11并发的订单号生成方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

要设计订单号首先需要订单号应该要具备的一些特性:

  1. 唯一性:这绝对是作为订单号最最最基本的特点;

  2. 高并发:并发能力越高越好;

  3. 趋势递增但是不能绝对递增:趋势递增会对现代数据库索引结构更友好,但是不要绝对递增是因为绝对递增的话,很容易暴露你系统每天产生的订单量;

  4. 利于以后的分库分表;

我的订单号方案

技术方案:
timestamp + 类用户ID + 随机数(可选)实现代码:
Long userId = 235689102L;
String last6 = userId<1000000?String.format("%06d", userId):String.valueOf(userId%1000000);
String orderId = System.currentTimeMillis() + last6;

这种方案是否具备上面提到的几个特点呢,让我们一起看一看:

  1. 唯一性:这种方案的订单号只有在同一个用户在同一毫秒内下多个订单才会出现出现,很显然,对于正常的用户行为,是不可能出现重复的,所以满足唯一性。

  2. 高并发:这个设计方案完全不依赖任何第三方服务,只通过一定的规则就能生成。所以这种方案不但高并发,而且零消耗。

  3. 递增性:因为订单号的前一部分是时间戳,所以满足趋势递增。并且,也满足非绝对递增的特性。

  4. 分库分表:假设分库分表因子为订单号最后6位数,那么无论是根据订单ID查询,还是根据用户ID查询,都不会涉及跨库跨表,效率非常高。至于根据商户编号查询商户的订单号,可以参考笔者另一篇文章《分库分表技术演进&最佳实践-修订篇》,有提到解决方案。

通过上面的分析可知,这种方案还是很不错的!而且,这种方案不需要依赖任何第三方服务,需要的硬件成本为零,老板最喜欢呀!当然,如果担心用户ID信息通过订单号暴露,可以先通过某种函数例如hash(userId),然后再生成订单号即可。伪代码如下:

Long userId = 235689102L;
Long hashId = hash(userId);
String last6 = hashId<1000000?String.format("%06d", hashId):String.valueOf(hashId%1000000);
String orderId = System.currentTimeMillis() + last6;
System.out.println(orderId);

 

  • 为什么这种方案利于分库分表?

我们知道作为一个订单表,最核心的查询有3类:根据订单号查询、根据用户ID查询、根据商户号查询,这三类查询占了订单表90%甚至更多的查询量。如果采用的是这里提到的时间戳+类用户ID的方案,那么根据订单号查询和根据用户ID查询都不涉及跨表,效率非常高。请看接下来的分析。

假设订单表按照订单号进行分表,并且分表算法为:hash(last6(orderId))%16,即根据订单号的最后6位数字hash后取模。这样的话,如下几个订单号就会分在同一个表假设t_order_5中,因为这几个订单号最后6位数字完全一样:

1573172799123 141618
1575878423467 141618
1583545280012 141618

然后,这几个订单表都是用户ID为182141618生成的(我们假设hash(182141618)%1000000=141618)。那么用户ID为182141618所生成的订单也会都落在表t_order_5中,因为hash(182141618)%1000000=141618,也就是说,查询条件带有userId=182141618的查询目标表都是t_order_5。事实上,这种方案就是所谓的因子分表法

接下来,我们可以看一下支付宝订单号又是如何设计的。

 

支付宝订单号方案

下面是3个真实的支付宝订单号(空格是为了更直观的看出支付宝订单号的特点):

20191024 2200141625 1404175790
20191025 2200141625 1404414662
20191026 2200141625 1405369921

分析这几个支付宝订单号,我们将其分解为3部分,从而得出支付宝的订单号的特点。你的支付宝订单号同样具备这样的特点:

时间戳 + 类用户ID + 递增的数值

通过对支付宝订单号的分解,我们很容易发现它的方案和前面提到的方案有异曲同工之妙:都有时间戳部分和类用户ID部分,此乃英雄所见略同也,哈哈哈!

这篇关于如何设计一个能扛住双11并发的订单号生成方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/700577

相关文章

MybatisGenerator文件生成不出对应文件的问题

《MybatisGenerator文件生成不出对应文件的问题》本文介绍了使用MybatisGenerator生成文件时遇到的问题及解决方法,主要步骤包括检查目标表是否存在、是否能连接到数据库、配置生成... 目录MyBATisGenerator 文件生成不出对应文件先在项目结构里引入“targetProje

Python使用qrcode库实现生成二维码的操作指南

《Python使用qrcode库实现生成二维码的操作指南》二维码是一种广泛使用的二维条码,因其高效的数据存储能力和易于扫描的特点,广泛应用于支付、身份验证、营销推广等领域,Pythonqrcode库是... 目录一、安装 python qrcode 库二、基本使用方法1. 生成简单二维码2. 生成带 Log

Python中的可视化设计与UI界面实现

《Python中的可视化设计与UI界面实现》本文介绍了如何使用Python创建用户界面(UI),包括使用Tkinter、PyQt、Kivy等库进行基本窗口、动态图表和动画效果的实现,通过示例代码,展示... 目录从像素到界面:python带你玩转UI设计示例:使用Tkinter创建一个简单的窗口绘图魔法:用

Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南

《Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南》在日常数据处理工作中,我们经常需要将不同Excel文档中的数据整合到一个新的DataFrame中,以便进行进一步... 目录一、准备工作二、读取Excel文件三、数据叠加四、处理重复数据(可选)五、保存新DataFram

SpringBoot生成和操作PDF的代码详解

《SpringBoot生成和操作PDF的代码详解》本文主要介绍了在SpringBoot项目下,通过代码和操作步骤,详细的介绍了如何操作PDF,希望可以帮助到准备通过JAVA操作PDF的你,项目框架用的... 目录本文简介PDF文件简介代码实现PDF操作基于PDF模板生成,并下载完全基于代码生成,并保存合并P

详解Java中如何使用JFreeChart生成甘特图

《详解Java中如何使用JFreeChart生成甘特图》甘特图是一种流行的项目管理工具,用于显示项目的进度和任务分配,在Java开发中,JFreeChart是一个强大的开源图表库,能够生成各种类型的图... 目录引言一、JFreeChart简介二、准备工作三、创建甘特图1. 定义数据集2. 创建甘特图3.

Java解析JSON的六种方案

《Java解析JSON的六种方案》这篇文章介绍了6种JSON解析方案,包括Jackson、Gson、FastJSON、JsonPath、、手动解析,分别阐述了它们的功能特点、代码示例、高级功能、优缺点... 目录前言1. 使用 Jackson:业界标配功能特点代码示例高级功能优缺点2. 使用 Gson:轻量

Redis KEYS查询大批量数据替代方案

《RedisKEYS查询大批量数据替代方案》在使用Redis时,KEYS命令虽然简单直接,但其全表扫描的特性在处理大规模数据时会导致性能问题,甚至可能阻塞Redis服务,本文将介绍SCAN命令、有序... 目录前言KEYS命令问题背景替代方案1.使用 SCAN 命令2. 使用有序集合(Sorted Set)

MyBatis延迟加载的处理方案

《MyBatis延迟加载的处理方案》MyBatis支持延迟加载(LazyLoading),允许在需要数据时才从数据库加载,而不是在查询结果第一次返回时就立即加载所有数据,延迟加载的核心思想是,将关联对... 目录MyBATis如何处理延迟加载?延迟加载的原理1. 开启延迟加载2. 延迟加载的配置2.1 使用

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超