概述
在大流量下订单号生成方法一文中介绍了如何生成不重复的订单号,主要原理是利用数据库自增ID。但是像业务流水号之类的,其实不利用数据库也是可以的,只是要保证唯一性,做起来不太好做。下文介绍一种方法来生成流水号,如果不是那种特别变态的调用量,产生重复的机会还是很少的。但是如果是那种无论如何都不能重复的,不建议用本文的方法了。
流水号生成规则
时间+四位的机器号+10位的随机数
时间的生成
时间的话,可以使用下面的方式来生成。
FastDateFormat.getInstance("yyyyMMddHHmmssSSS").format(new Date()))
使用apache的FastDateFormat线程安全的格式化时间,到毫秒。注意千万别用JAVA自带的SimpleDateFormat
,不是线程安全的,如果你一定要用SimpleDateFormat
的话,需要结合ThreadLocal
来实现。
机器号
这个可以先用JAVA代码获取机器的MAC地址。如何获取机器的MAC地址的代码,网上大把,这里贴一个用过的。
private static String getMacAddress() throws Exception {
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
if (null == networkInterface) {
continue;
}
byte[] macBytes = networkInterface.getHardwareAddress();
if (networkInterface.isUp() && !networkInterface.isLoopback() && null != macBytes && macBytes.length == 6) {
StringBuilder sb = new StringBuilder();
for (int i = 0, nLen = macBytes.length; i < nLen; i++) {
byte b = macBytes[i];
sb.append(Integer.toHexString((b & 240) >> 4));
sb.append(Integer.toHexString(b & 15));
if (i < nLen - 1) {
sb.append("-");
}
}
return sb.toString().toUpperCase();
}
}
return null;
}
上面的代码就获取到MAC地址,格式是:
xx-xx-xx-xx-xx-xx
得到MAC地址后,可以根据MAC地址获取它对应的CRC16校验码,可以简单的使用如下代码来获取:
private static int getCRC16Code(String macAddress) {
if (null == macAddress) {
return 0;
}
byte[] data = macAddress.getBytes(Charset.forName("utf-8"));
CRC16 crc16 = new CRC16();
for (byte b : data) {
crc16.update(b);
}
return crc16.value;
}
接下来可以根据这个CRC16校验码截取高四位。这个代码比较简单,就不贴了。
另外,也见过机器号是通过环境变量来读取的,把机器号配置在环境变量中,然后直接在代码里读取。也见过在配置中心配置的。
生成随机数
可以利用JAVA的AtomicInteger
来生成。
总结
如果你的应用是要给对方提供流水号的,那么如果对方使用for循环并且并发调用,还是有可能生成重复的流水号的,这种情况下,最好在客户端调用的时候,在for循环里sleep 一毫秒,降低并发。
另外有个建议,如果是对方的接口要求你传入一个唯一的流水号,最好在生成的流水号上加上自己系统的名字,这样服务方也可以通过看流水号,就知道是哪个系统过来的。
2018 博客之星
我最近在参与CSDN的博客之星评选,希望您投下宝贵的一票,多多支持我继续写博客,谢谢。