本文共 3084 字,大约阅读时间需要 10 分钟。
1.前言
这是我写的工具类之一:根据日期生成唯一顺序订单号。
用Java 配合 Redis 实现包含日期的顺序订单号的生成, 效率可以达到 2500+/s 1000W+/h 个 。
2.基本介绍
框架: Spring Boot
依赖: Redis
实现方式:生成订单号之前找到保存的最大ID值,并且设定过期时间(每天都从1开始生成);然后判断生成订单号队列里的订单号数量,如果达到阈值则生成新的一批订单号,如果没有达到阈值则直接返回订单号。
orderNoInitSize; //(order生成的速度)
orderNoCreateLength; //(需要重新生成的阈值)
orderLength; //(订单顺序号的位数 ,默认6位支持每天生成999999个订单号)
3.完整代码
@Override
public String getOrder(String type) {
DateFormat df = new SimpleDateFormat("yyyyMMdd");
String dayDf=df.format(new Date());
String orderKey=type.toString().concat("_").concat(dayDf);
if(getRedisSize(orderKey)<=orderNoCreateLength) {
this.generateInit(orderKey,type,dayDf);
}
return getOrderNo(orderKey);
}
//初始化
synchronized private void generateInit(String orderKey,String type,String dayDf) {
List orders=new ArrayList<>();
Long max=this.generate(orderKey.concat("_max"), 1, getTodayEndTime());
for(long i=max;i
orders.add(format(i,type.toString(),dayDf,orderLength));
}
redisTemplate.opsForList().leftPushAll(orderKey, orders);
redisTemplate.expireAt(orderKey, getTodayEndTime());
this.generate(orderKey.concat("_max"), orderNoInitSize-1, getTodayEndTime());
}
@SuppressWarnings("unused")
private String format(Long id,String prefix,String date,String minLength){
StringBuffer sb = new StringBuffer();
sb.append(prefix);
sb.append(date);
return sb.toString().concat(String.format("%1$0".concat(orderLength).concat("d"), id));
}
//通过key获取自增并设定过期时间
public Long generate(String key,Date expireTime) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
counter.expireAt(expireTime);
return counter.incrementAndGet();
}
//通过key获取增加的值 并设定过期时间
public long generate(String key,int increment,Date expireTime) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
counter.expireAt(expireTime);
return counter.addAndGet(increment);
}
// 获取当天过期时间
private Date getTodayEndTime() {
Calendar todayEnd = Calendar.getInstance();
todayEnd.set(Calendar.HOUR_OF_DAY, 23);
todayEnd.set(Calendar.MINUTE, 59);
todayEnd.set(Calendar.SECOND, 59);
todayEnd.set(Calendar.MILLISECOND, 999);
return todayEnd.getTime();
}
// 获取redis list size
private Long getRedisSize(String key) {
return redisTemplate.opsForList().size(key);
}
//获取订单号
private String getOrderNo(String key) {
return redisTemplate.opsForList().rightPop(key);
}
4.速度测试
Test 测试类,因机器配置不同执行时间会有差异
@Autowired
private OrderGenerateService orderGenerateService;
@Test
public void contextLoads() throws InterruptedException {
long startTime=System.currentTimeMillis();
ExecutorService executor=Executors.newFixedThreadPool(30);
for(int i=0;i<100000;i++) { executor.execute(new Runnable() { @Override public void run() { // TODO Auto-generated method stub System.out.println(orderGenerateService.getOrder("PA")); } }); } while(true) { int threadCount = ((ThreadPoolExecutor)executor).getActiveCount(); if(threadCount>=30) {
Thread.sleep(10);
continue;
}
if(threadCount<=0) {
break;
}
}
long endTime=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(endTime-startTime)+"ms");
}
程序运行时间: 32423ms
5.完整代码
6.完成
转载地址:http://glnuo.baihongyu.com/