问题及背景
再项目中需要传入一个支付的流水号,收单机构规定为15位。那么就需要保证这个15位的流水号是永不重复的。
解决方案
先获取13位时间戳,精确到毫秒级
获取一个自增长的数字为2位(实际需要字符串才能保证订单号长度固定)(线程同步)❗️❗️❗️
拼接他俩得到一个毫秒级99次并发不重复的流水号
解决代码
代码:
/**
* @Author liuyg
* @Description 同步获取一个顺序号
* @Date 2024/4/25 9:13
* @Return java.lang.String
*/
private static Integer serialNumber = 0;
private static synchronized String getSerialNumber() {
serialNumber++;
if (serialNumber >= 99) {
serialNumber = 0;
}
return java.lang.String.format("%02d", serialNumber);
}
/**
* @Author liuyg
* @Description 获取订单号
* @Date 2024/4/25 9:29
* @Return java.lang.String
*/
public static String createOrdeNo() {
String ordeNo = System.currentTimeMillis() + getSerialNumber();
return ordeNo;
}
测试代码:
public static void main(String[] args) {
long w = 0;
for (int q = 0; q < 10000; q++) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 99; i++) {
String outTradeNo = createOrdeNo();
list.add(outTradeNo);
}
long numDuplicates = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.values()
.stream()
.filter(count -> count > 1)
.count();
w += numDuplicates;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(w);
}
测试代码是循环10000轮次,每次生成99个,延迟1毫秒。模拟每毫秒99次并发的场景,不会出现重复流水号的场景,但是就局限于每毫秒99次的并发,超过了此方案必然重复
总结
虽然本方案局限于每毫秒99次的并发,但是目前我们项目这个场景是够用了😀😀😀
主要是通过每毫秒的速度之快,以及每毫秒上面加一个顺序数,保证同一毫秒级别并发的时候出现重复流水号的情况。当然也可以给createOrdeNo方法加synchronized关键字。
评论区