Java中流水编号的生成

在开发中,遇到这样一个需求,在介质资料新增时,需要生成一个介质编号,格式为”JZ+yyyyMMdd+4位递增数字”
先是使用百度找寻解决方法。解决方法

里面的查询缓存的方法在我这项目里没有,我也不会写,就自己想了个折中的方法。在请求这个接口的时候,先去数据库查询MAX(id),如果有,就在此基础上+1
如果没有,就初始化一个值1进行传参。相关代码如下:

点击查看代码


public class NumberUtils {

    /**
    * 生成14位唯一流水号,"JZ"+yyyyMMdd+4位数字
    * 4位数字,如:0001
    * @return
    */
    @NotNull
    public static String generateSerialNum(String str, Integer nowNum){
        // 定义需要返回的流水号
        String serialNum;
        // 先查询到今天的日期,格式:"yyyyMMdd"
        String todayDate = new SimpleDateFormat("yyyyMMdd")
                .format(new Date());
        // 固定字母前缀 拼接 今天日期,组成新的完整的前缀
        String prefixCode = str + todayDate;

        serialNum = getCode(prefixCode, nowNum);

        return serialNum;
    }

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

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

        // &#x5148;&#x62FC;&#x63A5;&#x524D;&#x7F00;
        code.append(prefix);
        // &#x518D;&#x62FC;&#x63A5;&#x6570;&#x5B57;
        code.append(num);
        return code.toString();
    }
}

后面被说不行,并发下不行。而且跟数据库连接效率也低。就想到了使用redis的incr方法。相关代码如下:

点击查看代码

public class NumberUtils {

    /**
    * &#x7F16;&#x53F7;&#x81EA;&#x52A8;&#x751F;&#x6210;
    * @param redisTemplate redis&#x6A21;&#x677F;
    * @param code &#x524D;&#x7F00; &#x9996;&#x5B57;&#x6BCD;&#x5927;&#x5199;
    * @param dateFormat &#x65E5;&#x671F;&#x683C;&#x5F0F;
    * @param nums &#x51E0;&#x4F4D;&#x6570;&#x5B57;
    * @return &#x7F16;&#x53F7;
    */
    @NotNull
    public static String generateSerialNum(@NotNull RedisTemplate<string,integer> redisTemplate,
                                           String code, String dateFormat, Integer nums) {
        // &#x4F7F;&#x7528;StringBuilder&#x62FC;&#x63A5;&#x5B57;&#x7B26;&#x4E32;
        StringBuilder sb = new StringBuilder();
        // &#x83B7;&#x53D6;&#x5F53;&#x524D;&#x65F6;&#x95F4;&#x5E76;&#x5B9A;&#x4E49;&#x65E5;&#x671F;&#x683C;&#x5F0F;
        String localDateFormat = DateUtils.localDateFormat(LocalDate.now(), dateFormat);
        sb.append(code);
        sb.append(localDateFormat);

        // &#x5C06;&#x62FC;&#x63A5;&#x597D;&#x7684;&#x5B57;&#x7B26;&#x4E32;&#x505A;key&#xFF0C;&#x83B7;&#x53D6;redis&#x4E2D;&#x7684;&#x6570;&#x636E;
        Integer i = redisTemplate.opsForValue().get(sb.toString());
        int increment;
        if (i != null) {
            // &#x5982;&#x679C;redis&#x4E2D;&#x6709;&#x6570;&#x636E;&#xFF0C;&#x5219;&#x4F7F;&#x7528;increment()&#x5C06;&#x6570;&#x636E;+1
            increment = Objects.requireNonNull(redisTemplate.opsForValue()
                                     .increment(sb.toString())).intValue();
        } else {
            // &#x5982;&#x679C;redis&#x4E2D;&#x6CA1;&#x6709;&#x6570;&#x636E;&#xFF0C;&#x5219;&#x4F7F;&#x7528;setIfAbsent()&#x5C06;&#x6570;&#x636E;&#x8BBE;&#x7F6E;&#x4E3A;1
            increment = 1;
            redisTemplate.opsForValue().setIfAbsent(sb.toString(),increment);
        }

        // &#x7B2C;&#x4E00;&#x6B21;format&#x683C;&#x5F0F;&#x5316;nums&#x4F4D;0&#xFF0C;&#x4E4B;&#x540E;&#x518D;&#x683C;&#x5F0F;&#x5316;increment
        sb.append(String.format(String.format("%%0%dd", nums), increment));
        return sb.toString();
    }
}
</string,integer>

然后说代码逻辑没问题,就是代码可以再优化,一通解释加我一通操作,最后代码如下:

点击查看代码

@Slf4j
public class NumberUtils {
    private NumberUtils() {}

    /**
    * &#x7F16;&#x53F7;&#x81EA;&#x52A8;&#x751F;&#x6210;
    *
    * @param redisTemplate redis&#x6A21;&#x677F;
    * @param code          &#x524D;&#x7F00; &#x9996;&#x5B57;&#x6BCD;&#x5927;&#x5199;
    * @param dateFormat    &#x65E5;&#x671F;&#x683C;&#x5F0F;
    * @param nums          &#x51E0;&#x4F4D;&#x6570;&#x5B57;
    * @return &#x7F16;&#x53F7;
    */
    @NotNull
    public static String generateSerialNum(RedisTemplate<string,integer> redisTemplate,
                                           String code, String dateFormat, Integer nums) {
        // nums&#x4F4D;&#x6570;&#x5B57;&#xFF0C;&#x4E0D;&#x591F;&#x7684;&#x524D;&#x9762;&#x8865;0
        val format = String.format("%%0%dd", nums);
        // &#x8FD4;&#x56DE;&#x62FC;&#x63A5;&#x597D;&#x7684;&#x7F16;&#x53F7;
        return code + DateUtils.localDateFormat(LocalDate.now(), dateFormat)
          // redisKey&#x7EC4;&#x6210;&#xFF1A;&#x524D;&#x7F00;+&#x683C;&#x5F0F;&#x5316;&#x540E;&#x7684;&#x5177;&#x4F53;&#x65E5;&#x671F;&#xFF0C;&#x786E;&#x4FDD;&#x6BCF;&#x5929;&#x90FD;&#x662F;&#x65B0;&#x7684;key&#xFF0C;&#x7F16;&#x53F7;&#x4ECE;0001&#x5F00;&#x59CB;
        + String.format(format, getIncrement(redisTemplate, code + DateUtils.localDateFormat(LocalDate.now(), dateFormat)));
    }

    private static Integer getIncrement(@NotNull RedisTemplate<string,integer> redisTemplate, String redisKey) {
        return Optional.ofNullable(redisTemplate.opsForValue().get(redisKey))
                // &#x8FD4;&#x56DE;redis&#x91CC;&#x7684;&#x503C; + 1
                .map(num -> Objects.requireNonNull(redisTemplate.opsForValue().increment(redisKey)).intValue())
                // &#x5982;&#x679C;redis&#x91CC;&#x6CA1;&#x6709;&#xFF0C;&#x5219;&#x63D2;&#x5165;1&#x5E76;&#x901A;&#x8FC7;&#x5224;&#x65AD;&#x63D2;&#x5165;&#x662F;&#x5426;&#x6210;&#x529F;&#x6765;&#x8FD4;&#x56DE;&#x521D;&#x59CB;&#x5316;&#x503C;1&#xFF0C;&#x5982;&#x679C;&#x63D2;&#x5165;&#x5931;&#x8D25;&#xFF0C;&#x5219;&#x8FD4;&#x56DE;&#x62FC;&#x63A5;null
                .orElse(Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(redisKey, 1)) ? 1 : null);
    }
}
</string,integer></string,integer>

Original: https://www.cnblogs.com/cyb-start/p/16254900.html
Author: 长夜余火
Title: Java中流水编号的生成

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/713732/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球