批次号/订单号生成

发布时间:2017-07-31
技术:Spring4.3.5+Mybatis3.26

概述

在系统内部或与其他系统进行对接对编码有一定自定义规则,包括批次号、订单号,比如 PCH20170727152245000001 编码规范 = 开头字母 + 年月日时分秒 + 序号 ,使用存储过程和不使用存储过程两种方式,数据都是存在 mysql 数据库中。

详细


更多个人文章请点击

一、准备工作

1、订单号数据存储在 Mysql 数据库中,需要安装 Mysql 数据库。

2、使用数据库存储过程生成编码和不使用存储过程在代码中生成编码,相同的是编码都是保存在数据库中。

二、程序实现

1、程序截图

1501347344494015101.png


2、实现思路

使用存储过程:在存储过程中进行查询和插入

不使用存储过程:在代码中先查询出来再进行插入

都是在数据库进行查询,然后插入


3、主要代码

存储过程如下:

BEGIN

-- 当前日期
DECLARE
    currentDate VARCHAR (15);

-- 离现在最近的满足条件的编码
DECLARE
    oldCode VARCHAR (25) DEFAULT '';

-- oldCode的流水号
DECLARE
    maxNo INT DEFAULT 0;

IF num = 4 THEN
    -- yyyy
    SELECT
        DATE_FORMAT(NOW(),'%Y') INTO currentDate;

ELSEIF num = 6 THEN
    -- yyyymm
    SELECT
        DATE_FORMAT(NOW(),'%Y%m') INTO currentDate;

ELSEIF num = 8 THEN
    -- yyyymmdd
    SELECT
        DATE_FORMAT(NOW(),'%Y%m%d') INTO currentDate;

ELSEIF num = 12 THEN
    -- yyyymmddHHii
    SELECT
        DATE_FORMAT(NOW(),'%Y%m%d%H%i') INTO currentDate;

ELSEIF num = 14 THEN
    -- yyyymmddHHiiss
    SELECT
        DATE_FORMAT(NOW(),'%Y%m%d%H%i%s') INTO currentDate;

END
IF;

-- 显示最后一条数据
SELECT
    IFNULL(code,'') INTO oldCode
FROM
    code_test
WHERE
    SUBSTRING(code,1,preLen) = pre
AND SUBSTRING(code,(preLen + 1),num) = currentDate
AND LENGTH(code) = preLen + num + noLen
ORDER BY
    id DESC
LIMIT 1;

-- 编码不为''截取编码的最后noLen位
IF oldCode != '' THEN

SET maxNo = CONVERT(
    SUBSTRING(oldCode, - noLen),
    DECIMAL
);

END
IF;

-- 如果流水号不足noLen位,用0填充左边
SELECT
    CONCAT(
        pre,
        currentDate,
        LPAD((maxNo + 1), noLen, '0')
) INTO newCode;

-- 插入数据
INSERT INTO
    code_test (code)
VALUES
    (newCode);

SELECT
    newCode;

END


入参为:

IN pre VARCHAR(32), IN preLen INT, IN num INT, IN noLen INT, OUT newCode VARCHAR(32)


不使用存储过程代码如下:

    //代码同步,防止高并发
    private final static ReentrantLock lock;
    static{
        lock = new ReentrantLock();
    }
    
    /**
     * 不使用存储过程
     */
    @Test
    public void codeTest2(){
        Map<String, Object> map = new HashMap<String, Object>();

        String pre = "PCH";
        Integer preLen = 3;
        Integer num = 4;
        Integer noLen = 4;
        
        Date curr = new Date();
        SimpleDateFormat formatter = null;

        switch (num) {
        case 4:
            formatter = new SimpleDateFormat("yyyy");
            break;
        case 6:
            formatter = new SimpleDateFormat("yyyyMM");
            break;
        case 8:
            formatter = new SimpleDateFormat("yyyyMMdd");
            break;
        case 12:
            formatter = new SimpleDateFormat("yyyyMMddHHmm");
            break;
        case 14:
            formatter = new SimpleDateFormat("yyyyMMddHHmmss");
            break;

        default:
            break;
        }

        String currentDate = formatter.format(curr);

        map.put("pre", pre);
        map.put("preLen", preLen);
        map.put("num", num);
        map.put("noLen", noLen);
        map.put("currentDate", currentDate);

        lock.lock();

        String newCode = "";
        String newNo = "";

        try {

            String oldCode = codeTestDao.getOldCode(map);

            if (StringUtils.isEmpty(oldCode)) {
                newNo = "1";
            } else {
                Integer maxNo = Integer.parseInt(oldCode.substring(oldCode.length() - noLen));
                newNo = String.valueOf(maxNo + 1);
            }

            int length = newNo.length();
            
            if(length > noLen){
                System.out.println("新流水号位数超限");
            }
            
            for (int i = 0; i < noLen - length; i++) {
                newNo = "0".concat(newNo);
            }

            newCode = pre + currentDate + newNo;

            CodeTest codeTest = new CodeTest();
            codeTest.setCode(newCode);

            codeTestDao.saveSelective(codeTest);

        } finally {
            lock.unlock();
        }

        System.out.println("生成的编码为:"+newCode);
    }

三、运行效果

1、将 db 文件夹下的 test.sql 导入数据库

2、修改 jdbc.properties 文件中 mysql 连接

3、执行 CodeJunitTest 类下的 两个测试方法

1501347916264090866.png



本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码