在前面我们介绍过雪花id相关的文章《java分布式项目之使用雪花算法生成唯一id》和《java分布式项目之使用tinyid生成唯一id》。在实际的生产环境中,我们会涉及到一些订单的场景,此时生成的订单号一般我们都会以字符串prefix+年月日+随机数的方式来组成,前缀主要是为了区别应用场景,年月日主要用于回查定位相关的信息,随机数是为了保证在高并发下不重复的问题。
但是这里的随机数我们还是需要保证一下,不能直接使用random.nextint函数,因为随机数也会出现重复的。需要一定的策略来保证。下面我们就来演示下生成订单号的工具类:
1、直接上工具类,示例代码如下:
package org.example.test; import java.text.SimpleDateFormat; import java.util.Date; public class DateUtils { private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS"); private static int sequence = 0; public static synchronized String getUid() { Date now = new Date(); String timestamp = dateFormat.format(now); if (sequence > 9999) { sequence = 0; } String sequenceString = String.format("%04d", sequence++); return "XF"+timestamp + sequenceString; } }
在这个类里面我主要是使用synchronized来保证同步,因为生成一个字符串的时间非常短,所以基于这里的话,我们可以忽略掉性能问题。
2)编写一个子线程的测试案例
这里我们使用上面的测试案例来编写一个子线程测试一下,为了方便统计,我们把结果写入到文件中去,示例代码如下:
package org.example.test; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.util.ArrayList; public class GenneralUnid implements Runnable { private int index; public GenneralUnid(int i) { System.out.println("当前index是:"+i); index = i; } private ArrayList<String> aaa = new ArrayList<String>(); @Override public void run() { for (int j = 0; j < 100000; j++) { DateUtils dateUtils = new DateUtils(); String uid = DateUtils.getUid(); aaa.add(uid); } try { FileUtils.writeLines(new File("D:\\aaa\\file" + index + ".txt"), aaa); } catch (IOException e) { throw new RuntimeException(e); } } }
3)编写测试代码
这里我们编写main函数的测试代码,示例代码如下:
package org.example.test; public class Test1 { public static void main(String[] args) { for(int i = 0; i< 30;i++){ new Thread(new GenneralUnid(i)).start(); } } }
4)运行测试
运行测试类,可以看到生成了很多文件
一共是30个线程,生成30个文件,然后我们上传到服务器上去,可以看到一共有300W条记录,去重后还是300W,如下图:
然后我们看看我们开的30个线程,每秒钟能生成多少个不重复的id:
我们拿20230822103420这个时间来查询下:
可以看到每秒钟有21W的id生成,所以这个生成唯一id是没问题的。
备注:
1、这里每秒钟生成21W,但是工具类里面最大只有9999,很多小伙伴很纳闷,为什么没重复,因为这里时间转换的时候还有毫秒SSS,所以21W的数据是正常的。
2、这里目前整个生成的号码字符串长度是23位,因此数据库里面也需要是23位的。
3、这里如果线程比较多,例如几百个,几千个,那么这里我们设置的9999的位数也是不够的,也会出现重复,此时需要做的就是增大这个9999的值,如下图:
增大之后需要测试下是否重复。
还没有评论,来说两句吧...