`
annan211
  • 浏览: 461711 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

高并发生成订单号(二)

 
阅读更多

银联16位数字订单号
永远不重复的生成算法

  请尊重知识,请尊重原创 更多资料参考请见  http://www.cezuwang.com/listFilm?page=1&areaId=906&filmTypeId=1
1、 前提背景
相信做过银联支付的都知道,银联的订单号要求商户提供一个不重复的16位数字订单号(不重复指的是对商户本身,不用考虑银联有多个商户会与其他商户的订单号重复)。16位数其实很短,要考虑每秒并发1w或者10w或100万时,重复订单号将数不过来。
需要考虑的因素:
 若使用数据库保存流水号,集群部署时,同步关键字不再有效。当然同步对性能也有非常大的影响;
 若使用时间,必须要精确到毫秒、微妙级别,长度就不止16位了。
 若使用数据库字段自增,数据库并发时硬件将吃不消。
 获取订单号时检查表的最大值,这种方案是最不可取的。

以下将给出本人经过深入研究的三种方案,按顺序,最优的方案为第三个。
备注:
如果要测试产生重复订单号的情况,可以建立一个表,把订单号字段设置为唯一性,然后开启1000或10000或更多的线程去请求方法,每个线程循环5次或10次来请求,在方法里面写插入语句。或者可以使用Apache的ab工具并发测试。
使用方法:ab -n5000 -c5000 http://192.168.1.102:8888/kjcx/aaa.action

2、 可选方案一
本方案使用的是当前时间,包括毫秒数、纳秒数,不需要数据库参与计算,性能不用说。
算法:

OrderId=
machineId+
(System.currentTimeMillis()+"").substring(1)+
(System.nanoTime()+"").substring(7,10);


讲解:
参数machineId:是集群时的机器代码,可以1-9任意。部署时,分别为部署的项目手动修改该值,以确保集群的多台机器在系统时间上不一致的问题(毫无疑问每台机器的毫秒数基本上不一致)。
参数System.currentTimeMillis():这是java里面的获取1970年到目前的毫秒数,是一个13位数的数字,与Date.getTime()函数的结果一样,比如1378049585093。经过研究,在2013年,前三位是137,在2023年是168,到2033年才199.所以,我决定第一位数字1可以去掉,不要占位置了。可以肯定绝大多数系统用不了10年20年。这样,参数2就变成了12位数的数字,加上参数1machineId才13位数。
参数System.nanoTime():这是java里面的取纳秒数,经过深入研究,在同一毫秒内,位置7,8,9这三个数字是会变化的。所以决定截取这三个数字出来拼接成一个16位数的订单号。
总结:理论上此方案在同一秒内,可以应对1000*1000个订单号,但是经过测试,在每秒并发2000的时候,还是会出现2-10个重复。

3、 可选方案二
本方案使用的是获得会话ID(sessionId)来产生hashCode。
算法:

OrderId=
machineId+
session().getId().hashCode();


讲解:
参数machineId不再讲解,与方案一致。
参数2 session().getId().hashCode()是值在web系统中获取用户浏览器与web容器的唯一会话编号,再把该会话ID转换为该字符串的hashCode值,如1939354961。该值可能是一个11位数的或10位数的,或者在前面还会出现-号,也就是有可能该值是负数,没关系,取正。然后再对该值进行左补0到15位数,基本上可以应对位数不一致的问题。
我们知道,hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值。可以想象,hashCode的值如果出现重复,那就是一个值了,而不是不同的值。又因为sessionId是客户端、与浏览器有关联的,所以基本上不会出现重复,但是如果用户在同一个会话有效期内、同一个版本的浏览器,生成2次就无效了,因为会话ID是一致的。
总结:该算法,可以确保不重复的概率很小,但是需要自己特殊处理同会话同浏览器生成1次以上订单号的问题,此算法没有经过调试,略过,您请看方案三。

4、 可选方案三
本方案在基于方案二的基础上做了修改,使用的使用UUID而不是会话id。
UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的,这个不重复性全世界人民都知道。当然,既然字符串值不重复,那对应的hashCode也是一样,不会重复。
算法:

OrderId=
machineId+
UUID.randomUUID().toString().hashCode();



讲解:
参数1不再解释。
参数2是值生成UUID然后取它的hashCode值,经过测试,完全没有一点问题。您可以开1000w的并发去测试插入吧,只要数据库不会报唯一性错误,那就没问题。
总结:
hashCode这个算法从搞软件开始到现在这么多年,一直没派上用场,这次大大的用上了。解决了问题。请同志们以后善用这个东西。
5、 附录:方案三的算法代码

6、	public static String getOrderIdByUUId() {
7、			int machineId = 1;//最大支持1-9个集群机器部署
8、			int hashCodeV = UUID.randomUUID().toString().hashCode();
9、			if(hashCodeV < 0) {//有可能是负数
10、				hashCodeV = - hashCodeV;
11、			}
12、			// 0 代表前面补充0     
13、			// 4 代表长度为4     
14、			// d 代表参数为正数型
15、			return machineId+String.format("%015d", hashCodeV);
16、		}



方案三其实也就一个函数,很简便。

最后:这是引自一个未知人的思想,不记得他的地址了。

 

分享到:
评论
3 楼 dida1990 2017-05-02  
啊喔,过去了这么久,不过还是评一个。
谁说uuid的hashCode不重复的啊,明显还是有可能重复,不然你去看看string的hashCode源码
2 楼 annan211 2017-01-02  
yclovesun 写道
使用了uuid,为什么还要machineId?uuid已经可以保证不重复了啊

  UUID理论上是不会重复,但是考虑到严格性和确保不重复,需要格外处理。
1 楼 yclovesun 2016-12-23  
使用了uuid,为什么还要machineId?uuid已经可以保证不重复了啊

相关推荐

    二次开发订单管理模块(带订单号)

    例如,引入智能校验机制,自动检测订单号的唯一性,避免重复下单。同时,可以增加对客户信息、商品信息和支付方式的有效验证。 2. **订单处理流程**:二次开发可能改进订单处理的自动化程度,例如,自动化分配库存...

    订单系统订单,可随意修改的订单系统

    系统应能有效地存储和检索订单信息,包括订单号、商品详情、价格、数量、付款方式、配送地址等,并确保数据的安全性和一致性。在可修改的系统中,用户可以便捷地更新订单状态,例如取消订单、更改配送地址或追加商品...

    SAP 采购订单 表关系

    - **AUFNR** - 订单号:关联工作订单表。 ##### 13. **EKET - 计划协议计划行** - **EBELN** - 采购凭证编号:采购凭证的编号。 - **EBELP** - 采购凭证的项目编号:采购凭证项目的唯一编号。 - **ETE** - 计划行...

    取消订单损失报告.doc

    在电子商务领域,取消订单是常见的业务现象,它可能由于各种原因发生,如客户变更需求、产品质量问题、供应链中断等。当订单被取消时,企业往往会遭受一定的经济损失,这些损失可能体现在多个方面,包括但不限于物料...

    易飞管理系统-订单管理系统.ppt

    2. **日常单据录入**:日常发生的销售订单、变更单、销货单等进行录入。 3. **应收票据管理**:处理客户的付款凭证,包括跟踪和管理应收账款。 4. **信息创建与核对**:确保输入数据的准确性和完整性。 5. **期初...

    计算机二级VisualFoxPro上机考试题库与答案解析53.docx

    接着,使用SQL SELECT语句进行查询,查询内容包括所有订单号、订购日期、器件号、器件名和总金额(按订单号升序排序,相同订单号时按总金额降序排序)。查询结果应存储到新的表"RESULTS"中,其中数据源来自"ORDER_...

    C#生成流水号小代码

    流水号通常用于标识唯一性记录,例如订单编号、文档编号等。该代码通过结合当前日期与递增的序列号来生成唯一的流水号。 #### 二、关键代码分析 ##### 1. **命名空间引入** ```csharp using System; using ...

    SAP 消息号C6013解决方案

    #### 知识点二:订单状态与退货操作的关系 - **订单状态`CRTD`**:表示订单处于创建状态。在此状态下,订单尚未经过后续的审批或确认流程,因此可能存在某些限制,比如无法直接进行退货操作。 - **退货操作**:退货...

    数据分析精华案例-天猫订单综合分析

    - **退款金额**:订单退款的金额,如果订单没有发生退款,则为0。 **指标维度梳理**: - **结果指标**:销售量(以订单实际支付金额衡量)。 - **过程指标**: - **UV**:订单创建数量。 - **转化率**:从订单...

    PHP秒杀系统 高并发高性能的极致挑战-

    - **乐观锁**:假设不会有并发冲突发生,在更新数据时仅在最后阶段进行版本号检查。 - **悲观锁**:假设会发生并发冲突,在操作数据前先加锁,确保数据的一致性。 在实际开发中,可以根据业务需求选择合适的锁机制...

    营销转化 - 如何提高订单成交率.pdf

    文档强调了报价是国际贸易订单成单的必备因素,并详述了报价六要素:产品货号、名称、种类、规格、包装规格(内外)、采购数量以及成交价格。这些要素构成了专业报价回复的基础,对客户来说也是判断产品价值和采购的...

    扫描终端二次开发,条码装箱检验系统

    操作员首先扫描外箱的条码,这通常包含产品的整体信息,如订单号或批次号。接着扫描内箱条码,内箱条码则包含了内含商品的具体信息。通过对比内外箱条码,系统能判断装箱是否正确,防止错误的发生。 2. **二次开发...

    二级采购师考试案例分析练习题.pdf

    1. **供应商关系管理**:对于像149号部件这样具有高安全风险的组件,Acme公司应该与供应商建立紧密的战略合作关系。这种关系不仅基于价格,更应注重质量保证和风险管理。供应商的选择不能仅基于短期成本优势,而应...

    SAP按销售订单生产和标准结算配置及操作手册.docx

    - 保存订单后,退回到需求分析的功能,刷新后可获取生成的生产订单号。 ##### 3.12 出库发货 当生产完成后,需要进行出库发货,即将成品从仓库移交给客户。具体步骤如下: - **MB1A**:执行出库发货操作。 #### ...

    SAP创建销售订单时,出现“定价条件错误:必要条件 MWST 丢失”错误,查错及其解决方法

    ### SAP创建销售订单时,“定价条件错误:必要条件 MWST 丢失”的查错及解决方法 #### 一、问题背景 在使用SAP系统创建销售订单的过程中,有时会遇到一个较为常见的错误:“定价错误:必要条件 MWST 丢失 (Pricing ...

    高并发的抢购功能

    2. **使用乐观锁**:乐观锁是一种基于版本号或时间戳的机制,它假设冲突发生的概率较低,每次更新数据前都会检查版本号是否一致,以此来避免并发修改的问题。这种方法在并发度不是特别高的情况下效果较好。 3. **...

    SAP_CO_PC-SAP按销售订单生产和标准结算配置及操作手册-V0-trigger_lau.docx

    - 保存订单后,可以退回到需求分析的功能,刷新后获得生成的生产订单号。 ##### 9. 发料(Order-MB1A) - **操作**: - 使用事务代码MB1A进行发料操作,确保原材料准确无误地分配到相应的生产订单上。 #### 四、...

    ectouch 微信支付成功后订单状态未改变的解决办法

    - 确认是否正确接收了微信支付平台发送的数据,并且能够解析出订单号等关键信息。 - 检查是否有将支付成功的订单状态更新到数据库的逻辑。确保这部分代码被执行并且没有语法错误或逻辑错误。 2. **审查核心处理...

    某超市-电脑使用手册范本.doc

    - 使用F2进入“订单号”栏位,输入需查询的订单号(例如123610)。 - 按F12进行查询。 - 展示订单详情,包括商品描述、订货单位、单位商品货号、订货数量、收货数量等信息。 #### 3. 订单信息展示示例 - **订单...

    零件提交保证书[PSW].doc

    * 采购订单号:依据采购订单填入代号 * 零件重量:填入用千克表示的零件实际重量,精确到小数点后四位 * 检查辅具代码:如果有辅助工具(检具)用于尺寸检验,应填入其代号 * 检查辅助工程变更等级与日期:若该检具...

Global site tag (gtag.js) - Google Analytics