订单号3个性质:1.唯一性 2.不可推测性 3.效率性
可选方案一
本方案使用的是当前时间,包括毫秒数、纳秒数,不需要数据库参与计算,性能不用说。
public static String genId(String machineId){ String orderId = machineId + (System.currentTimeMillis() + "").substring(1) + (System.nanoTime() + "").substring(7, 10); System.out.println(orderId); return orderId;}
讲解:
参数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个重复。
可选方案二
本方案基于UUID。
UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的,这个不重复性全世界人民都知道。当然,既然字符串值不重复,那对应的hashCode也是一样,不会重复。
算法:
OrderId=
machineId+
UUID.randomUUID().toString().hashCode();
讲解:
参数1不再解释。
参数2是值生成UUID然后取它的hashCode值,经过测试,完全没有一点问题。您可以开1000w的并发去测试插入吧,只要数据库不会报唯一性错误,那就没问题。
总结:
hashCode这个算法从搞软件开始到现在这么多年,一直没派上用场,这次大大的用上了。解决了问题。请同志们以后善用这个东西。
5、 附录:方案二的算法代码
public static String getOrderIdByUUId(String machineId) { int hashCodeV = UUID.randomUUID().toString().hashCode(); if (hashCodeV < 0) {//有可能是负数 hashCodeV = -hashCodeV; } // 0 代表前面补充0 // 4 代表长度为4 // d 代表参数为正数型 String orderId=machineId + String.format("%015d", hashCodeV); System.out.println(orderId); return orderId; }
方案二其实也就一个函数,很简便。