ID生成,主键生成工具

package com.iwhalecloud.basetool.asyncimpexpbase.common;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.security.SecureRandom;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * KeyGenerator 主键生成工具
 *
 * @author huang.wu@iwhalecloud.com
 * @date 2021/7/11
 */
public class KeyGenerator {

    public static final int INCREMENR_LIMIT = 89999;
    public static final int INCREMENT_INITIA = 10000;
    public static final int DATE_MILL_FACTOR = 1000;

    private KeyGenerator() {
    }


    /**
     * 时间戳格式
     */
    private static final String DATE_FORMAT = "yyyyMMddHHmmss";
    /**
     * 随机数位数
     */
    private static final int RANDOM_BOUND = 9000;
    /**
     * 时间填充位数
     */
    private static final int SEQ_TIME_PAD_SIZE = 4;
    /**
     * 随机数填充位数
     */
    private static final int RANDOM_PAD_SIZE = 1000;
    /**
     * 填充数
     */
    private static final String PAD_CHAR = "0";


    /**
     * 防止重复的自增
     */
    private static AtomicInteger increment = new AtomicInteger(INCREMENT_INITIA);

    private static SecureRandom random = new SecureRandom();

    /**
     * 表主键生成
     *
     * @return
     */
    public static String generateId() {
        Date now = new Date();

        String dateStr = DateFormatUtils.format(now, DATE_FORMAT);

        String seqFromTime = StringUtils.leftPad(Long.toString(now.getTime() % DATE_MILL_FACTOR), SEQ_TIME_PAD_SIZE, PAD_CHAR);


        String randomStr = String.valueOf(random.nextInt(RANDOM_BOUND) + RANDOM_PAD_SIZE);


        int inc = increment.getAndIncrement();
        //因为无锁,如果有多个线程同时执行这个方法调用,最大可能会被加到90099,也就是说以上算法如果有超过10000个线程并发调用会有问题
        //此情况下可以考虑扩大自增范围
        //同时如果并发太高,1ms内创建的订单数超过79998,即qps超过79999万时也有一亿分之一的概率重复
        if (increment.get() >= INCREMENR_LIMIT) {
            increment.set(INCREMENT_INITIA);
        }

        return dateStr + seqFromTime + inc + randomStr;

    }

    /**
     * 表主键生成,可指定前缀
     *
     * @return
     */
    public static String generateId(String prefix) {
        Date now = new Date();

        String dateStr = DateFormatUtils.format(now, DATE_FORMAT);

        String seqFromTime = StringUtils.leftPad(Long.toString(now.getTime() % DATE_MILL_FACTOR), SEQ_TIME_PAD_SIZE, PAD_CHAR);


        String randomStr = String.valueOf(random.nextInt(RANDOM_BOUND) + RANDOM_PAD_SIZE);


        int inc = increment.getAndIncrement();
        //因为无锁,如果有100个线程同时执行这个方法调用,最大可能会被加到90099,也就是说以上算法如果有超过10000个线程并发调用会有问题
        //此情况下可以考虑扩大自增范围
        //同时如果并发太高,1ms内创建的订单数超过79998,即qps超过7999万时也有一亿分之一的概率重复
        if (increment.get() >= INCREMENR_LIMIT) {
            increment.set(INCREMENT_INITIA);
        }

        return (prefix != null && prefix.length() > 0 ? prefix : "") + dateStr + seqFromTime + inc + randomStr;

    }

    public static void main(String[] args) {
        System.out.println(generateId());
        System.out.println(generateId().length());

        System.out.println(generateId("110"));
        System.out.println(generateId("110").length());
    }


}

上一篇:吐血整理!宅家36天咸鱼翻身入职腾讯,绝对干货


下一篇:PHP 常见加密方式