本文介绍如何使用最简单的方法产生一个全局唯一的流水号,支持集群,性能可靠,并且经过实际的应用

唯一流水号的格式为当前系统时间+当前服务器编号+并发序列号,长度最短可为17位,每毫秒支持生成多个并且支持集群部署

废话不多说,直接上demo,以下demo只需要把连接数据库的工具类Dbutil换成你自己的就可以直接使用了,demo运行成功后需要注意下文中的注意事项

package com.helianxiaowu.utils;import com.newcapec.dao.SysClusterNodeDao;import org.apache.commons.lang.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.net.InetAddress;import java.net.UnknownHostException;import java.util.Date;import java.util.Map;import java.util.Random;/** * @title 唯一流水号生成器 * @desc * @author helianxiaowu * @date 2020/1/18 下午 11:48 */public class PrimaryGenerator {    private static final Logger logger = LoggerFactory.getLogger(PrimaryGenerator.class);    // 单例模式    private static PrimaryGenerator primaryGenerator = new PrimaryGenerator();    private PrimaryGenerator() {}    /**     * 对外提供单例对象     * @return     */    public static PrimaryGenerator getInstance() {        return primaryGenerator;    }    /**     * @title 生成一个唯一编号     * @desc     * @author W.jw     * @date 2018/5/9 14:23     */    public synchronized String make() {        // 获取当前系统的时间戳        Date now = new Date();        long timestamp = now.getTime();        /**         * 判断当前时间戳和上一次产生流水号的时间是否相等         *   如果不相等,可以使用当前时间戳         *   如果相等,判断并发数是否达到最大值         *     如果达到最大值,需要等待下一个毫秒作为新的时间戳         *     如果没有达到最大值,则可以使用当前序列值         */        if (this.lastTime == timestamp) {            serial = serial + 1 ;            if (serial == maxSerial) {                timestamp = this.tilNextMillis(this.lastTime);            }        } else {            serial = 0;        }        // 将当前系统时间赋值给lastTime,方便下一次做判断        this.lastTime = timestamp;        // 保证序列号是3位,产生的订单号长度一样。也可以不补位,订单号长度会短点        String.format("%03d", serial);        // 把当前系统时间格式化为yyMMddHHmmssSSS        String time = DateUtil.dateToString(now, "yyMMddHHmmssSSS");        // 唯一流水号 = yyMMddHHmmssSSS+当前服务器唯一编号+序列号        StringBuilder sb = new StringBuilder(time).append(getMachineId()).append(serial);        return sb.toString();    }    /**     * 等待下一个毫秒     * @param currentTime 当前系统时间     * @return     */    private long tilNextMillis(long currentTime) {        long timestamp = System.currentTimeMillis();        while (timestamp <= currentTime) {            timestamp = System.currentTimeMillis();        }        return timestamp;    }    /**     * 获取当前服务器的编号,固定长度为2位     *   从数据库中获取当前服务器的ip在服务器中对应的唯一id     *   如果id存在,则使用id作为唯一编号     *   如果id不存在,获取当前服务器的ip并插入数据库得到id     *     * @return     */    private String getMachineId() {        if (this.machineId != null) {            return this.machineId;        }        /**         * 获取当前服务器的ip,如果没有获取到ip则随机返回一个两位数         */        String ip = this.getIp();        if (ip == null) {            // 随机返回两位数并且加上100,保证随机返回的数值和数据库中的id值不冲突            return String.format("%02d", new Random().nextInt(100) + 100);        }        /**         * 从数据库中获取当前服务器的ip对应的id值         *   如果没有则插入一条记录并获取id值         *   如果有则直接使用         */        Map<String, Object> nodeMap = DbUtil.getByIp(ip);        if (nodeMap == null || nodeMap.size() == 0) {            try {                DbUtil.save(ip);                nodeMap = DbUtil.getByIp(ip);            } catch (Exception e) {                logger.error("插入集群节点信息失败:{}" , e);                return String.format("%02d", new Random().nextInt(100) + 100);            }        }        this.machineId = String.format("%02d", nodeMap.get("id"));        return this.machineId;    }    /**     * 获取当前服务器ip     * @return     */    private static String getIp() {        InetAddress address = null;        try {            address = InetAddress.getLocalHost();        } catch (UnknownHostException e) {            e.printStackTrace();            return null;        }        return address.getHostAddress();    }    /**     * 最后一次生成订单号的时间,格式yyMMddHHmmssSSS     */    private long lastTime = 0;    /**     * 当前服务器在集群内的编号     */    private String machineId;    /**     * 并发序列号     */    private long serial = 0L;    /**     * 允许并发的最大值     */    private final int maxSerial = 999;}

注意事项

1.本demo需要保证单例运行,否则会产生重复的流水号。保证单例模式的方法有很多种,如:使用单例模式或把demo交由spring管理,demo中使用的是单例模式

2.序列号的最大值不可以无限大,需要考虑服务器的配置。建议使用999,每毫秒产生1000个流水号,一秒就可以产生60*1000个流水号,并发性已经很好了

3.本demo中机器编号限制为两位,最大支持99个服务器,如果你的集群中服务器数量超过99个,则需要把编号的位数扩大。当然,服务器的数量不足10个的话,也可以调小,流水号的长度也会短点


扫码关注我的公众号

每天进步一点点,不负光阴,度几扶人

如何产生一个全局唯一的流水号(附demo)相关推荐

  1. Android 10 + 适用于国内各大手机厂商的开放匿名设备标识(OAID),若不支持OAID则随机生成一个全局唯一标识(GUID)

    源码见:https://github.com/gzu-liyujiang/Android_CN_OAID 本项目用于获取国内各大Android手机厂商的开放匿名设备标识(OAID).遵循谷歌官方使用A ...

  2. Spring Boot 工程集成全局唯一ID生成器 Vesta

    2019独角兽企业重金招聘Python工程师标准>>> 本文内容脑图如下: 文章共 760字,阅读大约需要 2分钟 ! 概 述 在前一篇文章 <Spring Boot工程集成全 ...

  3. 如何在分布式场景下生成全局唯一 ID ?

    作者 l 会点代码的大叔(CodeDaShu) 在分布式系统中,有一些场景需要使用全局唯一 ID ,可以和业务场景有关,比如支付流水号,也可以和业务场景无关,比如分库分表后需要有一个全局唯一 ID,或 ...

  4. c#获取对象的唯一标识_在 Java 中利用 redis 实现分布式全局唯一标识服务

    作者: 杨高超 juejin.im/post/5a4984265188252b145b643e 获取全局唯一标识的方法介绍 在一个IT系统中,获取一个对象的唯一标识符是一个普遍的需求.在以前的单体应用 ...

  5. springboot整合dubbo_springboot整合dubbo设置全局唯一ID进行日志追踪

    1.新建项目 利用idea创建一个父项目,三个子项目,其中一个项目为生产者,一个项目为消费者,一个为接口等公共服务项目,生产者和消费者需要有web依赖,可以作为tomcat容器启动. 2.项目依赖 & ...

  6. 微信用户全局唯一标识_分布式系统的唯一ID生成算法对比

    在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识. 那么如何实现全局唯一id呢?有以下几种方案. (1)方案一:独立数据库自增id 这个方案就是说你的系统每次要生成一个id,都是往一个独立库 ...

  7. dubbo protocol port 消费者端_springboot整合dubbo设置全局唯一ID进行日志追踪

    击上方蓝色"程序员白楠楠",选择"设为星标" 作者:松下听泉 出处:https://blog.csdn.net/weixin_39427718 1.新建项目 利 ...

  8. springboot整合dubbo设置全局唯一ID进行日志追踪

    1.新建项目 利用idea创建一个父项目,三个子项目,其中一个项目为生产者,一个项目为消费者,一个为接口等公共服务项目,生产者和消费者需要有web依赖,可以作为tomcat容器启动. 2.项目依赖 & ...

  9. UUID全局唯一标识符

    UUID 是通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分. UUID 的目的是让分布式系 ...

最新文章

  1. 人对光波的三种特性_花友小叶投稿:养花一年了,三种绿植基本不用管,没光也不怕...
  2. C++虚继承下的内存模型(二)
  3. python实现提取jira bug列表
  4. 国嵌c语言深度,国嵌C语言3部全
  5. centos调整页面大小_这2种方法都能调整PDF文档的纸张大小
  6. SQL查询语句,怎样查询重复数据
  7. python画柱状图-Python Excel 绘制柱形图
  8. xBIM 基础07 创建WebBIM文件
  9. foc学习笔记2——svpwm
  10. GROUP_CONCAT()用法
  11. 电子烟脱去糖衣后,下一步往哪走?
  12. 你写的api接口代码真是_有哪些好玩的免费的API接口?
  13. 安卓手机做服务器(django),完成废物利用
  14. windows7台式计算机网线连接,win7台式机连接wifi的方法步骤详解(2)
  15. 迷你星域冒险服务器维护中,迷你世界星域冒险攻略 星域冒险快速通关技巧[多图]...
  16. u盘里删除的文件可以恢复吗?分享解决方法
  17. Substance Designer 井盖
  18. Androd studio无线调试及镜像投屏
  19. 新版qq新增的功能(屏幕录制 屏幕翻译 屏幕文字识别 屏幕截图)
  20. [讨论]一个真正的IT人来谈中国与印度的软件

热门文章

  1. C语言中access函数
  2. C#winform连接数据库实现登陆注册(数据库的安装与配置)
  3. iPhone X 适配
  4. 【SSH】--SSH框架简介
  5. TM4C123G学习记录(2)--GPIO
  6. 练习-Java输入输出之字节数据输入输出之综合练习
  7. 数据结构 — 浅析红黑树原理以及实现
  8. STM32F4设置NVIC中断优先级分组
  9. 解决苹果无线鼠标、键盘或触控板无法被 Mac 识别的方法
  10. python里的map是什么意思_map在python中什么意思