创建基于时间的 UUID

概述

在本文中,我们将会 对 UUIDs 和基于时间的 UUIDs(time-based UUIDs) 进行一些探讨。

当我们在对基于时间的 UUIDs 进行选择的时候,总会遇到一些好的方面和不好的方面,如何进行选择,也是我们将要简要探讨的内容。

同时我们还会对可能会使用类库进行一些比较和探索,以便于我们更好的做出选择。

UUIDs 和 基于时间的 UUIDs

UUID 的全称是 Universally Unique Identifier,中文为通用唯一识别码。

当生成 UUID 的时候,系统总会自动生成一个 128 位的 UUID。基于 UUID 的生产算法的不同,我们会有不同的版本。

UUID 的主要目的就是用来在全世界中唯一标识一个数据,而且需要保证生成的 UUID 在全世界范围内是不重复的。因此我们可以用来标识一个上下文,包括数据库系统,计算机系统中的消息,分布式系统中的对象等等。

为了实现这个目标,我们需要确保哪怕是在同一个时间瞬间生成的 UUID 也是不相同,这样能够让我们更好的利用 UUID 在分布式计算机系统中标识存在的对象。

基于时间的 UUID,通过字面就可以了解到,这个 UUID 是基于时间的,实际上这个 UUID 存在 UUID 设计中的第一版。

这个版本是基于随机数的,使用的基数为每 100 纳秒为一个单位,时间的起点为1582年10月15日。同时还需要加上当前计算机的网卡物理地址(MAC)。

在后续的版本中,UUID (v6 和 v7)也是基于时间的 UUID 生成算法,可以说是基于 UUID v1 的更新版本。

UUID v1 因为是基于时间的,所以具有排序功能,这个在对数据库的设计上就很有帮助,当我们使用 UUID v1 来作为 PK(主键)的时候,我们就知道了,我们创建的这条记录的时间戳是什么时候,这个对我们在对数据进行调试和问题分析的时候就很有帮助了。

有优势就自然会有劣势,因为我们是基于时间创建 UUID 的,那么在同一个系统产生 UUID 冲突的可能性就会大很多,假设在同一个时间点,我们创建了很多个 UUID,那么大概率就会有出现冲突,重复出现的情况。

在本文的后部分,我们会对这个可能出现的情况进行一些探索。

另外一个原因,就是在 UUID v1 版本中使用主机地址这种做法会潜在的增加系统的安全性问题。这就是 UUID v6 尝试希望解决的问题。

对比程序

为了对可能出现的 UUID 冲突进行演示。我们尝试使用程序来对比可能出现 UUID 冲突的可能性。

这个程序,将会创建 128 个线程,在每个线程中将会生成 100,000 个 UUID。

首先我们对需要使用的变量来进行一些初始化:

    int threadCount = 128;int iterationCount = 100_000;Map<UUID, Long> uuidMap = new ConcurrentHashMap<>();AtomicLong collisionCount = new AtomicLong();long startNanos = System.nanoTime();CountDownLatch endLatch = new CountDownLatch(threadCount);

如上面的程序所表示的内容,我们定义了 128 个线程,在这 128 个线程中,我们会循环 100,000 次。

同时,我们还初始化了一个 ConcurentHashMap 把我们生成的 UUID 存储到 ConcurentHashMap 中。

同时,我们还会记录出现 UUID 冲突的次数。

为了记录程序的性能,我们对程序开始时间和程序的结束也都进行了存储。在最后我们定义了一个 latch 等待所有线程的执行完成。

当定义完成后变量后,我们就需要启动线程并对线程序进行执行。

    for (long i = 0; i < threadCount; i++) {long threadId = i;new Thread(() -> {for (long j = 0; j < iterationCount; j++) {UUID uuid = Generators.timeBasedGenerator().generate();Long existingUUID = uuidMap.put(uuid, (threadId * iterationCount) + j);if(existingUUID != null) {collisionCount.incrementAndGet();}}endLatch.countDown();}).start();}

在 UUID 的创建过程中,我们使用了 fasterxml 包中的 Generators,这个 Generators 使用的是 java.util.UUID 类来创建的。

在创建 UUID v1 的使用,使用 fasterxml 是我们常用的做法。

当 UUID 创建后,我们就把创建好的 UUID 存储到 Map 中,UUID 为 map 的 Key,当我们的 UUID 重复出现冲突的时候,Map 将会提示错误,我们程序就会捕获这个错误,然后把出现错误的计数器 + 1。

endLatch.await();
System.out.println(threadCount * iterationCount + " UUIDs generated, " + collisionCount + " collisions in "+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos) + "ms");

在程序的最后,CountDownLatch 的 await() 方法会等待所有的线程完成。

当所有线程完成后,我们就会把结果打印在计算机屏幕上。

下面就让我们开始对程序进行运行。

12800000 UUIDs generated, 0 collisions in 16913ms

上面出现了程序的运行结果,我们可以看到并没有出现 UUID 冲突的问题。

uuid-creator

Java UUID Creator 小巧并且使用比较广泛的 UUID 生成器。

使用这个生成器能够为你生成各种 UUID,但从使用的情况上来看并不如 java-uuid-generator 使用得更加频繁。

依赖

如希望在项目中使用这个生成器,需要把这个生成器添加到依赖中。

com.github.f4b6a3 uuid-creator 5.3.7 Copy

使用

这个库提供了 3 个基于时间生成的 UUID 方法。

  • UuidCreator.getTimeBased() – 遵守 RFC-4122 规范生成基于时间的 UUID
  • UuidCreator.getTimeOrdered() – 使用 gregorian epoch 处理的新 UUID 格式
  • UuidCreator.getTimeOrderedEpoch() – 使用 Unix epoch proposed 处理的新 UUID 格式

当我们导入包后,可以直接使用下面的方法来进行使用。

System.out.println("UUID Version 1: " + UuidCreator.getTimeBased());
System.out.println("UUID Version 6: " + UuidCreator.getTimeOrdered());
System.out.println("UUID Version 7: " + UuidCreator.getTimeOrderedEpoch());

我们可以看到生成 UUID 为我们通常认识的 UUID 格式。

UUID Version 1: 0da151ed-c82d-11ed-a2f6-6748247d7506
UUID Version 6: 1edc82d0-da0e-654b-9a98-79d770c05a84
UUID Version 7: 01870603-f211-7b9a-a7ea-4a98f5320ff8

冲突校验

我们还可以使用上面提供的生成代码放我我们开始的一部分使用的冲突校验程序中运行。

运行的结果为:

12800000 UUIDs generated, 0 collisions in 2595ms

通过这个库生成的基于时间的 UUID 我们也没有发现有冲突的情况。

Java UUID Generator (JUG)

依赖

Java UUID Generator (JUG) 在很多项目中因为要生成 UUID 而被使用,其中包括了有 生成UUID 的方法和格式化输出等一些内容。

生成的 UUID 是按照 (RFC-4122) 标准来生成的。

使用下面的代码来添加依赖,当前使用的最新版为 5.0.0

<dependency><groupId>com.fasterxml.uuid</groupId><artifactId>java-uuid-generator</artifactId><version>5.0.0</version>
</dependency>

使用

这个库也同时提供了 3 个方法来生成基于时间的 UUID(包括 v1,v6 和 v7)。

我们可以使用下面的方法来进行命令的调用:

System.out.println("UUID Version 1: " + Generators.timeBasedGenerator().generate());
System.out.println("UUID Version 6: " + Generators.timeBasedReorderedGenerator().generate());
System.out.println("UUID Version 7: " + Generators.timeBasedEpochGenerator().generate());

当程序完成运行后,可以从控制台中看到输出:

UUID Version 1: e6e3422c-c82d-11ed-8761-3ff799965458
UUID Version 6: 1edc82de-6e34-622d-8761-dffbc0ff00e8
UUID Version 7: 01870609-81e5-793b-9e4f-011ee370187b

校验

将新的生成程序替换掉我们原有的代码的时候,我们可以对生成进行输出校验。

12800000 UUIDs generated, 0 collisions in 15795ms

从上面的输出来看,针对代码我们并没有发现有 UUID 冲突的问题。

但是针对运行结果,生成 UUID 的时间是不同的,这是因为 JUG 的生成速度通常要慢一点,对于我们 UUID 来说如果不大量一次性生成 UUID,这个通常不会是太大的问题。

在项目中,通常需要选择项目已有的依赖,可能在现有的项目中,使用 java-uuid-generator 库的情况要相对多一点。

结论

在本文中,我们对需要生成基于时间的 UUID 进行了一些探讨。同时基于时间的不同,UUID 有不同的版本。

JDK 自己并没有提供快速的基于时间的 UUID 生成方法。

JDK 中的 UUID.randomUUID() 方法生成的是 UUIDv4 的方法。

基于时间的 UUID 生成,我们通常会依赖使用第三方的类库。

创建基于时间的 UUID - Java - iSharkFly概述在本文中,我们将会 对 UUIDs 和基于时间的 UUIDs(time-based UUIDs) 进行一些探讨。 当我们在对基于时间的 UUIDs 进行选择的时候,总会遇到一些好的方面和不好的方面,如何进行选择,也是我们将要简要探讨的内容。 同时我们还会对可能会使用类库进行一些比较和探索,以便于我们更好的做出选择。 UUIDs 和 基于时间的 UUIDsUUID 的全称是 Universally Unique Identi…icon-default.png?t=N7T8https://www.isharkfly.com/t/uuid/15686

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/4595.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2路模拟音频光端机 JR-CA02

概述 JR-CA02光端机由发送机JR-CA02 Tansmitter和接收机JR-CA02 Receiver组成&#xff0c;通过一定距离长度的光纤相连接&#xff0c;传输2路Audio模拟音频&#xff08;即1路立体声&#xff09;。且每路音频分配输出。 JR-CA02光端机具有运行主要技术参数的监测功能&#xff…

【AGX】Ubuntu20.04 + ROS_ noetic+ 大疆Mid360激光 雷达评测

大家好&#xff0c;我是虎哥&#xff0c;最近组装机器人&#xff0c;使用到了大疆孵化的圳市览沃科技有限公司&#xff08;简称Livox览沃科技&#xff09;推出的觅道系列全新混合固态激光雷达Mid-360&#xff0c;顺便试试效果&#xff0c;也记录一下使用入门过程。 "觅道M…

MATLAB : interp1()用法介绍

目录 一、基本语法&#xff1a; 二、实例&#xff1a; 1.样条拟合减振器阻尼曲线 ​2.PP拟合时间温度曲线 interp1 是 MATLAB 中的一个函数&#xff0c;用于在一维数据上执行插值操作。这个函数可以帮助你估计或计算已知数据点之间未知点的值。以下是 interp1 函数的基本用…

分类预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多特征分类预测

分类预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多特征分类预测 目录 分类预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多特征分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现POA-BP鹈鹕算法优化BP神经网络多特征分类预测&#xff08;Matlab实…

MySQL——88张表汇总——DDL+外键

外键er图 88张表 /* Navicat MySQL Data TransferSource Server : MyList Source Server Version : 50726 Source Host : localhost:3309 Source Database : schooldbTarget Server Type : MYSQL Target Server Version : 50726 File Encoding …

《深入解析Windows操作系统》第3章读书笔记

1、陷阱分发&#xff1a;中断和异常是导致处理器转向正常控制流之外代码的两种操作系统条件。陷阱的定义如下&#xff1a;当异常或者中断发生时&#xff0c;处理器捕捉到一个执行线程&#xff0c;并且将控制权转移到操作系统中某一个固定地址处。在Windows系统中&#xff0c;处…

Pycharm:常用插件安装和使用

简介&#xff1a;好用的插件可以美化界面或者提升效率&#xff0c;使工作事半功倍。 推荐插件&#xff1a; 1、CSV插件&#xff1a;美化csv数据展示 2、Translation&#xff1a;翻译的插件&#xff0c;可以进行中英互译 3、CodeGlance&#xff1a;代码小地图 4、Markdown …

代码随想录:二叉树29-30

目录 701.二叉搜索树中的插入操作 题目 代码&#xff08;迭代法走一边&#xff09; 代码&#xff08;递归法走一边&#xff09; 450.删除二叉搜索树中的节点 题目 代码&#xff08;递归法走一边&#xff09; 701.二叉搜索树中的插入操作 题目 给定二叉搜索树&#xff…

【软考高项】二十七、范围管理6个过程

一、规划范围管理 1、定义、作用 定义&#xff1a;为了记录如何定义、确认和控制项目范围及产品范围&#xff0c;而创建范围管理计划的过程作用&#xff1a;在整个项目期间对如何管理范围提供指南和方向 2、输入 项目章程 项目管理计划&#xff1a;质量管理计划、项目生命周…

编程本源

文章目录 引言编程的本质工作与编程编程的未来 引言 知乎上有一个热门的问题&#xff0c;什么是人生的顶级享受&#xff1f; 看到这个问题我回想到了多年前&#xff0c;那个炎热的午后&#xff0c;我在学校的图书馆里&#xff0c;一边参照书籍&#xff0c;一边用着一部破旧的t…

使用STM32CubeMX对STM32F4的CAN1/2/3配置及接收中断开启

目录 1. CAN配置1.1引脚&#xff08;STM32F413VGT6-LQFP100&#xff09;1.2 时钟1.3 RCC配置1.4 CAN1配置1.5 CAN2配置1.6 CAN3配置1.7 输出设置 2. CAN代码2.1 CAN初始化2.2 CAN滤波器设置2.3 CAN使能2.4 激活中断2.5 CAN发送函数2.6 CAN回调函数2.7 main之后的代码 1. CAN配置…

【无监督+自然语言】 GPT,BERT, GPT-2,GPT-3 生成式预训练模型方法概述 (Generative Pre-Traning)

主要参考 【GPT&#xff0c;GPT-2&#xff0c;GPT-3 论文精读【李沐论文精读】-2022.03.04】 https://www.bilibili.com/video/BV1AF411b7xQ/ 大语言模型综述&#xff1a; https://blog.csdn.net/imwaters/article/details/137019747 GPT与chatgpt的关系 图源&#xff1a;L…

java多功能手机

随着科技的发展&#xff0c;手机的使用已经普及到每个家庭甚至个人&#xff0c;手机的属性越来越强大&#xff0c;功能也越来越多&#xff0c;因此人们在生活中越来越依赖于手机。 任务要求&#xff0c;使用所学知识编写一个手机属性及功能分析程序设计&#xff0c;测试各个手机…

JEECG/SpringBoot集成flowable流程框架

IDEA安装Flowable BPMN visualizer插件 pom.xml中引入flowable相关依赖 <dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version></dependency><depe…

PHP 错误 Unparenthesized `a ? b : c ? d : e` is not supported

最近在一个新的服务器上测试一些老代码的时候得到了类似上面的错误&#xff1a; [Thu Apr 25 07:37:34.139768 2024] [php:error] [pid 691410] [client 192.168.1.229:57183] PHP Fatal error: Unparenthesized a ? b : c ? d : e is not supported. Use either (a ? b : …

Docker镜像和容器操作

目录 一.Docker镜像创建与操作 1. 搜索镜像 2. 获取镜像 3. 镜像加速下载 4. 查看镜像信息 5. 查看下载的镜像文件信息 ​编辑6. 查看下载到本地的所有镜像 7. 根据镜像的唯一标识ID号&#xff0c;获取镜像详细信息 8. 为本地的镜像添加新的标签 9. 删除镜像 10. 存入…

【Prometheus】了解你的Prometheus指标

简单Prometheus查询用于指标检查 作者&#xff1a;Michal Kazmierczak 来源&#xff1a;mkaz.me 基数是关键。 它很容易失控&#xff0c;就像任何组合爆炸的实例一样。 这&#xff0c;再加上90%的指标从未被访问过的说法&#xff0c;创造了一个值得探索的领域。 观察性云供应…

复杂Python代码看不懂,分享两个工具!

复杂Python代码看不懂&#xff0c;分享两个工具&#xff0c;事半功倍&#xff01; Ryven Ryven是一个Python代码可视化工具&#xff01; 精进地址&#xff1a;https://github.com/leon-thomm/Ryven 一些案例&#xff0c; Ryven可视化操作矩阵 Ryven可视化冒泡排序算法 Ryv…

Three.js和Cesium.js中坐标

在了解Three.js和Cesium.js前先了解并弄清楚图形学关于空间的基本概念流程&#xff1a; 计算机图形学 图形学中涉及到多个坐标空间&#xff0c;这些空间之间的变换是图形渲染中的核心部分。下面是一些常见的图形学空间及其变换顺序&#xff1a; 对象空间&#xff08;Object Sp…

Python快速入门1数据类型(需要具有编程基础)

数据类型&#xff1a; Python 3.0版本中常见的数据类型有六种&#xff1a; 不可变数据类型可变数据类型Number&#xff08;数字&#xff09;List&#xff08;列表&#xff09;String&#xff08;字符串&#xff09;Dictionary&#xff08;字典&#xff09;Tuple&#xff08;元…