项目中业务编号的实现(业务码+日期+自增序列)

目录

  • 1. 实现思路
  • 2. 代码实现
  • 3. 总结
  • 参考

做项目的时候,经常会有自动生成业务编码的需求,比如插入数据的时候需要生成如下产品编号:P-(年份日期和三位序列号),比如P-20180727001

1. 实现思路

  1. 使用业务编号+当前日期获得redis的key值;
  2. 使用redis的incr来原子性地获得其对应的自增数;
  3. 避免redis的数据冗余,需要在第一次incr的时候使用expireAt设置其数据当天24点过期。

这样即可在并发情况下获得不重复的相应编码。

2. 代码实现

public interface CodeGenerateService {

    /**
     * 根据编号类型生成相应的编号
     *
     * @param bizCode         编号类型
     * @param inrNumberLength 自增编号的长度
     *
     * @return 编号
     */
    String generateCode(String bizCode, int inrNumberLength);
}
@Service
public class CodeGenerateServiceImpl implements CodeGenerateService {

    private static final String SERIAL_GENERATE_PREX = "com.demo:serial_number";

    @Resource
    private CacheClient cacheClient;

    private static String getRedisKey(String bizType) {
        //获得当前日期
        String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
        return SERIAL_GENERATE_PREX + ":" + bizType + "-" + date;
    }

    /**
     * 获得自动补0的相应位数的值
     *
     * @param seq    数值
     * @param length 长度
     *
     * @return 一定位数的序列号
     */
    private static String getSequence(long seq, int length) {
        String str = String.valueOf(seq);
        int len = str.length();
        if (len > length) {
           return str;
        }
        int rest = length - len;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < rest; i++) {
            sb.append('0');
        }
        sb.append(str);
        return sb.toString();
    }

    /**
     * 获取某一天的0时0分0秒0毫秒
     *
     * @param amount 日增减量
     *
     * @return 时间
     */
    private Date getDay(int amount) {
        // 获取当前日期
        Calendar calendar = Calendar.getInstance();
        // 加一天
        calendar.add(Calendar.DAY_OF_MONTH, amount);
        // 清空时/分/秒/毫秒
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    @Override
    public String generateCode(String bizCode, int inrNumberLength) {
        String key = getRedisKey(bizCode);
        long number = cacheClient.incr(key);
        if (String.valueOf(number).length() > inrNumberLength) {
            //抛出自定义异常
            throw new SerialRangException("编码超出范围!");
        }
        if (number == 1) {
            cacheClient.expireAt(key, getDay(1).getTime() / 1000);
        }
        return key + getSequence(number, inrNumberLength);
    }

    @Override
    public String generateCode(String bizCode) {
        return this.generateCode(bizCode, 3);
    }

}

调用

codeGenerateService.generateCode("P")

后打印出来的编号为:P-20180917001

查看redis的存储值如图:

图中已有该key存储的值,且已设置了超时时间为当天的24点,可以满足项目的需求

3. 总结

利用redis的incr原子操作来获得唯一编号,此方法可保证在并发情况下编号的唯一性,但不能保证连续性,比如需要一次就生成连续的多个编号,需要使用来实现。

参考

  1. 流水号的生成(日期+业务码+自增序列)

原文地址:https://www.cnblogs.com/ading-blog/p/9664533.html

时间: 2024-08-30 12:34:31

项目中业务编号的实现(业务码+日期+自增序列)的相关文章

vue项目中使用qrcode生成二维码

1.安装:npm install qrcode 2.html: 1 <template> 2 <div> 3 <div id="code"></div> 4 <canvas id="canvas"></canvas> 5 </div> 6 </template> 3.逻辑: 1 import QRCode from 'qrcode 2 export default { 3

vue项目中批量打印二维码

前提:项目中要打印的二维码为后台返回,批量选择后,点击打印,先打开二维码预览界面,再执行打印. 以下代码中 codePicList为选中的二维码数组.重点css:page-break-after:always 在元素后插入分页符;在打印时,要分页(需求是每个二维码打印在一张纸上) // 此代码为浏览界面遍历出来的要打印的多个二维码<ul id="codeImgviewer" v-if="codePicList != null && codePicList

在JEE项目中实施SSL双向认证

一.为什么要实施双向认证(Why) 双向认证一般使用在B2B系统或企业内部系统中,目的就是阻止无关人员访问系统,哪怕就一个登录页面也不行.只有系统管理员给你发放了证书,你才能访问到该系统. 二.准备工作(Getting ready) 1. 你系统中要有JDK 2. 你要有一个Servlet容器,这里使用tomcat7 3. 下载BouncyCastle安全工具包,如果你使用Maven管理依赖,请加入下面的依赖项 1 2 3 4 5 6 7 8 9 10 <dependency>        

Java算法之递归打破及在真实项目中的使用实例

开心一笑 刚才领导问开发:"你觉得这个项目的最大风险是什么",开发说:"加班猝死" , 气氛尴尬了一分钟!!! 提出问题 1.递归算法简单复习 2.如何实现递归算法与真实项目接口??? 3.如何打破递归算法??? 解决问题 1.首先练习下网上一些递归经典题 1 package com.hwy.test; 2 3 /** 4 * 递归函数测试 5 * Created by Ay on 2016/7/2. 6 */ 7 public class RecursionTes

java 项目中几种O实体类的概念

经常会接触到vo,do,dto的概念,本文从领域建模中的实体划分和项目中的实际应用情况两个角度,对这几个概念进行简析. 得出的主要结论是:在项目应用中,vo对应于页面上需要显示的数据(表单),do对应于数据库中存储的数据(数据表),dto对应于除二者之外需要进行传递的数据. 一.实体类 百度百科中对于实体类的定义如下: 实体类的主要职责是存储和管理系统内部的信息,它也可以有行为,甚至很复杂的行为,但这些行为必须与它所代表的实体对象密切相关. 根据以上定义,我们可以了解到,实体类有两方面内容,存储

在iOS中使用ZBar扫描二维码

最近在做的项目中需要用到二维码扫描功能,之前在Android中使用过ZXing识别二维码,ZXing也有对应的iOS版本,经过了解,ZBar也是一个常用的二维码识别软件,并分别提供了iOS和Android的SDK可供使用,最终我选择了ZBar进行二维码识别,它的注释清晰,便于使用. ZBar为我们提供了两种使用方式,一种是直接调用ZBar提供的ZBarReaderViewController打开一个扫描界面,另一种方式是使用ZBar提供的可以嵌在其他视图中的ZBarReaderView,实际项目

Web API项目中使用Area对业务进行分类管理

在之前开发的很多Web API项目中,为了方便以及快速开发,往往把整个Web API的控制器放在基目录的Controllers目录中,但随着业务越来越复杂,这样Controllers目录中的文件就增加很快,难以管理,而且如果有不同业务模块有重复的控制器名的话,还需要尽量避免.引入Area的作用就是把控制器按照不同的业务模块进行区分,方便管理,而且控制器名称可以重名. 1.Web API项目引入Area进行分类 Area在项目中可以称之为区域,每个Area代表应用程序的不同功能模块,Area 使每

业务编号生成器

在我们实际做项目的过程中,时常需要生成一些跟业务相关的一些唯一的业务编号,这些编号又需要一定的规则,一般是每生成一个新的编号是在前一个编号的集成上尾号递增1个单位,下面是我业余时间写的一个编号生成器,直接贴代码: /** * 唯一业务编号生成器 * @param flag 业务前缀标识 * @return * @throws Exception */ public synchronized String getBusinessNum(String flag) throws Exception{

谈谈23种设计模式在Android源码及项目中的应用

本文首发于个人博客:Lam's Blog - 谈谈23种设计模式在Android源码及项目中的应用,文章由MarkDown语法编写,可能不同平台渲染效果不一,如果有存在排版错误图片无法显示等问题,烦请移至个人博客,如果个人博客无法访问可以留言告诉我,转载请声明个人博客出处,谢谢. 前言 本文将结合实际谈谈23种设计模式,每种设计模式涉及 * 定义:抽象化的定义与通俗的描述,尽量说明清楚其含义与应用场景 * 示例:如果项目中有使用过该模式,则会给出项目中的代码,否则会给出尽可能简单好理解的java