高并发生成订单号

银联16位数字订单号
永远不重复的生成算法
  请尊重知识,请尊重原创 更多资料参考请见  http://www.cezuwang.com/listFilm?page=1&areaId=906&filmTypeId=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
二、 可选方案一 
本方案使用的是当前时间,包括毫秒数、纳秒数,不须要数据库参与计算,性能不用说。
算法:java

Java代码 web

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个重复。
三、 可选方案二
本方案使用的是得到会话ID(sessionId)来产生hashCode。
算法:算法

Java代码 数据库

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次以上订单号的问题,此算法没有通过调试,略过,您请看方案三。
四、 可选方案三
本方案在基于方案二的基础上作了修改,使用的使用UUID而不是会话id。
UUID是指在一台机器上生成的数字,它保证对在同一时空中的全部机器都是惟一的,这个不重复性全世界人民都知道。固然,既然字符串值不重复,那对应的hashCode也是同样,不会重复。
算法:浏览器

Java代码 session

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



讲解:
参数1再也不解释。
参数2是值生成UUID而后取它的hashCode值,通过测试,彻底没有一点问题。您能够开1000w的并发去测试插入吧,只要数据库不会报惟一性错误,那就没问题。
总结:
hashCode这个算法从搞软件开始到如今这么多年,一直没派上用场,此次大大的用上了。解决了问题。请同志们之后善用这个东西。
五、 附录:方案三的算法代码并发

Java代码dom

public static String getOrderIdByUUId() {  
    int machineId = 1;//最大支持1-9个集群机器部署  
    int hashCodeV = UUID.randomUUID().toString().hashCode();  
    if(hashCodeV < 0) {//有多是负数  
        hashCodeV = - hashCodeV;  
    }  
    // 0 表明前面补充0       
    // 15 表明长度为15     
    // d 表明参数为正数型  
    return machineId+String.format("%015d", hashCodeV);  
}  


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

相关文章
相关标签/搜索