订单号生成的一些想法

订单号生成的一些想法

背景

  早上QA小姐姐发现线上有个报错,过去一看,采购单号生成异常,后台duplicate key,也就是说生成了重复单号。这个模块之前不是我写的(这个哥们刚离职了),而后来的领料单号的生成我重新写了下,规则比较简单,重复率也比较低,大家有好的方案也可以分享下。

正文

  首先,背景是我们这里需要一个18位的单号(有多种类型:采购、发货、领料等),订单号之类的基本规则:唯一、无序(特殊情况会要求排序、增量等),我们这里定了相应的格式:4位shopId + 2位订单类型编码 + 8位年月日 + 4位字符,

例如:0004CK201805080005。而原来哥们最后四位是用递增来生成的,0001之类的,而且是从数据库读取最新生成的单号,截取最后四位然后加1,这样的问题很明显:多机器(集群)时,或者有并发时很容易生成重复单号导致报错,由于我们这里是内部管理系统,并发量不大,但还是发生报错。还有连续生成的规则,容易被恶意爬取推算出每日的单量等。

  然后,基于原来的规则,我把最后的4为字符改为随机,加入了0-9、A-Z共36个字符,方法如下:

    private static String[] chars = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
            "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y",
            "Z" };

    /**
     * 
     * @Description:生成指定位数随机字符
     * @param length
     *            位数
     * @return String
     * @exception:
     * @author: wws
     * @time:2018年5月8日 下午4:18:58
     */
    private static String generateCode(int length) {
        StringBuilder shortBuffer = new StringBuilder();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        for (int i = 0; i < length; i++) {
            String str = uuid.substring(i * 4, i * 4 + 4);
            int x = Integer.parseInt(str, 16);
            shortBuffer.append(chars[x % chars.length]);
        }
        return shortBuffer.toString();
    }

  这样我们生成的4位数的组合理论上重复的概率是很低的,适合中小的系统使用。

其他生成方法

  1. 使用mysql自增id,优点:简单、保证唯一性;缺点:过于简单、且数据日渐增加、没有区分度(不同业务订单类型无法分辨)等

  2. UUID存储,优点:生成简单、无消耗;缺点:长度过长、没区分度、无序(数据位置无规则,可能影响到索引)、不安全(基于mac地址生成,可能导致泄露)等

  3. snowflake(Twitter),优点:不依赖数据库、性能好、单机递增;缺点:强依赖机器时钟、分布式下可能不同步等

  4. 美团的leaf(https://tech.meituan.com/MT_Leaf.html)。美团这里提供的思路很清晰,针对取号、时钟回拨等问题进行了分析,也提供了相应的解决(预警)方案,推荐大家看下。

posted @ 2018-08-13 15:47 .Zing 阅读( ...) 评论( ...) 编辑 收藏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值