基于redis生成自增流水号(格式:标志位 + 年月日时分秒 + 自增流水号)

       最近开发时,又遇到一个需求,后端需要生成自增的流水号,流水号格式一般就是:标志位 + 年月日时分秒 + 一定位数的流水号  组成,例如: T20190809135743000001 。

根据先前的查询和总结实现,现在对该需求的解决方法做一个整理记录。

       先前在网上看各位大佬对自增流水号的处理,一般分成三种:

      1. 通过在Java类中生成;

      2.依托数据库自增函数生成;

      3.依托redis自增生成

       因为我当前项目中本身就整合redis,而且redis是单线程,且基于内存操作,速度快,实现自增流水号代码也简单,所以我选用的是第三种。

        实现自增流水号,格式 标志位 + 年月日时分秒 + 一定位数的自增流水号 ,首先把这个分成两部分,一部分是前面的标志位 + 年月日时分秒,另一部分是一定位数的自增流水号,分别实现,最后拼接输出即可。

第一步:

生成流水号第一部分:标志位 + 年月日时分秒,这个很简单,不多说,代码如下:

        StringBuffer sbuffer = new StringBuffer();
        sbuffer.append("T");        //标志位
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        sbuffer.append(sdf.format(new Date()));     //年月日时分秒

第二步,调用redis的自增函数,获得流水号第二部分,自增

    //设置6自增6位,用于补全操作
    private static final String STR_FORMAT = "000000";


    /**
     * redis流水号自增
     * @param key        自己设置,保存当前自增值
     * @param liveTime   在redis中的缓存时间,方法中设置单位(秒/分/天……)
     * @return
     */
    public String incr(String key, long liveTime) {
        RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, stringRedisTemplate.getConnectionFactory());
        Long increment = entityIdCounter.getAndIncrement();

        if ((null == increment || increment.longValue() == 0) && liveTime > 0) {//初始设置过期时间
            entityIdCounter.expire(liveTime, TimeUnit.DAYS);    //设置自增值过期时间,liveTime 过期时间;TimeUnit.DAYS 过期时间单位,我这边设置为天
        }
        if (increment == 0) {           
            increment = increment + 1;
        } else if (increment > 999999){    
            increment = 1L;
        }
        //位数不够,前面补0 
        DecimalFormat df = new DecimalFormat(STR_FORMAT);    
        return df.format(increment);
    }

上述方法中,需要注意:

      1.保证每一天的流水号都是从01开始,所以我们的自增流水号对应的key必须要带上当天日期,例如:T20190809

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");    
String incKey = "T" + dateFormat.format(new Date());

     2. 设置自增值的过期时间,即什么时候让redis销毁无用的保存自增值的key

     3.保证流水号输出的位数不变,需要对自增值做位数补0操作

     4.当前流水号大于设置的位数时,需要从头开始计数。

 

只要把上述两个代码片段结果拼接在一起,就能得到我们需要的自增流水号:T20190809135743000001

    @Override
    public String selectTaskNo() {
        //格式:T+yyyymmddHHmiss+6位流水
        StringBuffer sbuffer = new StringBuffer();
        sbuffer.append("T");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        sbuffer.append(sdf.format(new Date()));
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String incKey = "T" + dateFormat.format(new Date());
        String no = incr(incKey, 1);
        sbuffer.append(no);
        System.out.println(">>>>>>>>>>>" + sbuffer.toString());
        return sbuffer.toString();
    }

用 postMan 并发测试当前接口(并发值:100),控制台输出正确值,没有出现乱序现象

基于redis生成自增流水号(格式:标志位 + 年月日时分秒 + 自增流水号)_第1张图片

基于redis生成自增流水号(格式:标志位 + 年月日时分秒 + 自增流水号)_第2张图片

你可能感兴趣的:(JavaWeb)