如何根据日期+数字生成流水号

生成流水号,在企业中可以说是比较常见的需求,尤其是订单类业务。
一般来说,需要保证流水号的唯一性。
如果没有长度和字符的限制,那么直接使用UUID生成一个唯一字符串即可,具体可参考我的这篇文章:java生成类似token的唯一随机字符串

也可以直接使用数据库表中的主键,主键就是唯一的。

那么,如果限制了流水号必须多少位,这种怎么生成呢?

可以采用"前缀+日期+数字"的方式(ps:此方式是需要用到缓存的)
前缀:为了更好的标识这个流水号是属于哪种类型;
日期:为了防止重复;
数字:为了表示当前的流水所处序号。

需求:生成一个17位数的唯一流水号,“LSH”+yyyyMMdd+6位数字

下面,就是具体的代码实现,具体内容可参考注释

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.concurrent.atomic.AtomicInteger;

public class SerialNoTest {

    public static void main(String[] args) {
        String serialNo = generateSerialNo();
        System.out.println("生成的流水号:"+serialNo);
    }

    /**
     * 生成17位唯一流水号,"LSH"+yyyyMMdd+6位数字
     * 6位数字,如:000001
     * @return
     */
    private static String generateSerialNo(){
        //定义需要返回的流水号
        String serialNo = null;
        //先查询到今天的日期,格式:"yyyyMMdd"
        String todayDate = new SimpleDateFormat("yyyyMMdd")
                                .format(new Date());
        //固定字母前缀 拼接 今天日期,组成新的完整的前缀,也就是缓存的key
        String cacheKey = "LSH"+todayDate;
        //再通过key查询缓存有没有num数据,缓存操作根据自身项目封装工具类
        Long codeNum = cacheService.getCache(cacheKey, Long.class);
        //如果缓存查询有值,数值+1,再赋值给下一个流水号
        if (null != codeNum) {
            codeNum = codeNum + 1L;
        } else {
            //如果缓存查询没值,直接赋值为1
            codeNum = 1L;
        }
        //流水号 = 缓存key + 拼接的数值 = 前缀 + 日期 + 拼接的数值
        serialNo = getCodeOfSix(cacheKey, codeNum.intValue());
        //设置缓存,调用此方法,会自动将key所对应的value+1,保存时长:今天剩余的时间
        cacheService.incr(cacheKey, getSeconds());
        return serialNo;
    }


    /**
     * 将数值拼接成对应的位数
     * @param prefix  前缀:"LSH"+yyyyMMdd
     * @param nowNum  当前要生成的数字
     * @return 拼接好的流水号
     */
    public static String getCodeOfSix(String prefix,int nowNum ) {
        //需要返回的code
        StringBuilder codeSb = new StringBuilder();
        //需要拼接的数字
        StringBuilder numSb = new StringBuilder();
        //封装的数字对象,里面 value 加了 volatile关键字,保证了线程安全
        AtomicInteger count = new AtomicInteger(nowNum);

        //将数值补足为6位字符串
        if (count.get() < 10) {
            numSb.append("00000").append(count.get());
        } else if(count.get() < 100){
            numSb.append("0000").append(count.get());
        }else if(count.get() < 1000){
            numSb.append("000").append(count.get());
        }else if(count.get() < 10000){
            numSb.append("00").append(count.get());
        }else if(count.get() < 100000){
            numSb.append("0").append(count.get());
        } else if (count.get() >= 100000) {
            numSb.append(count.get());
        }

        //先拼接前缀
        codeSb.append(prefix);
        //再拼接数字
        codeSb.append(numSb);
        return codeSb.toString();
    }


    /**
     * 获取当天结束还剩余多少秒
     * @return
     */
    public static int getSeconds(){
		//获取今天当前时间
        Calendar curDate = Calendar.getInstance();
		//获取明天凌晨0点的日期
        Calendar tommorowDate = new GregorianCalendar(
                curDate.get(Calendar.YEAR),
                curDate.get(Calendar.MONTH), 
                curDate.get(Calendar.DATE) + 1,
                0, 0, 0);
		//返回 明天凌晨0点 和 今天当前时间 的差值(秒数) 
        return (int)(tommorowDate.getTimeInMillis() - curDate .getTimeInMillis()) / 1000;
    }
}

假如今天是2021年4月22日,运行项目,生成的第1个流水号则为:LSH20210422000001
第2个流水号则为:LSH20210422000002,依次类推。

需要注意的是:
如果限制了位数,6位数字每天最多能生成10w个流水号,所以,这个数字位数根据具体业务量进行调整。
如果每天的生成数量量不到1w,那么使用4位数字即可。

  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
Java生成订单号(日期+流水号),可以使用SimpleDateFormat类和AtomicInteger类来实现。 1. 获取当前日期,可以使用SimpleDateFormat类将当前时间格式化为指定的日期格式,比如"yyyyMMdd"。 ```java SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); String currentDate = dateFormat.format(new Date()); ``` 2. 生成流水号,可以使用AtomicInteger类来维护一个自增的流水号。每次生成订单号时,调用incrementAndGet()方法获取下一个流水号。 ```java AtomicInteger sequence = new AtomicInteger(0); int nextSequence = sequence.incrementAndGet(); ``` 3. 将日期流水号拼接生成订单号。 ```java String orderNumber = currentDate + String.format("%04d", nextSequence); ``` 这里使用了String类的format()方法来保证流水号的位数,比如如果流水号是1,则格式化为"0001",如果流水号是12,则格式化为"0012"。 完整的代码如下: ```java import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.atomic.AtomicInteger; public class OrderNumberGenerator { private static AtomicInteger sequence = new AtomicInteger(0); public static String generateOrderNumber() { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); String currentDate = dateFormat.format(new Date()); int nextSequence = sequence.incrementAndGet(); String orderNumber = currentDate + String.format("%04d", nextSequence); return orderNumber; } public static void main(String[] args) { String orderNumber = generateOrderNumber(); System.out.println(orderNumber); } } ``` 每次调用generateOrderNumber()方法可以生成一个新的订单号,格式为"yyyyMMdd0001"、"yyyyMMdd0002"等。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值