创建基于时间的 UUID

news2024/11/26 23:54:35

概述

在本文中,我们将会 对 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.coloradmin.cn/o/1631901.html

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

相关文章

代码+视频,R语言绘制生存分析模型的时间依赖(相关)性roc曲线和时间依赖(相关)性cindex曲线

ROC曲线分析是用于评估一个因素预测能力的手段&#xff0c;是可以用于连续型变量分组的方法。在生存分析中&#xff0c;疾病状态和因素取值均会随时间发生变化。而标准的ROC曲线分析将个体的疾病状态和因素取值视作固定值&#xff0c;未将时间因素考虑在分析之中。在这种情况下…

一加Ace3/12/Ace2pro手机ColorOS14刷KernelSU内核ROOT-解决无限重启变砖

一加Ace3/一加12/一加11等手机升级了安卓14底层&#xff0c;并且ColorOS版本也更新到了14版本界面和功能都比之前的系统表现更加优秀&#xff0c;但刷机方面&#xff0c;相对之前存在一些差异&#xff0c;特别是KernelSU内核级别root权限&#xff0c;不再支持一键刷入KernelSU通…

【Linux网络】SSH--远程控制与访问

目录 一、SSH远程管理 1.SSH的定义 2.远程传输的种类 3.OpensSSH 4.SSH客户端与服务端 二、配置OpenSSH服务器 1.sshd_config配置文件的常用选项设置 2.sshd 服务支持两种验证方式 1&#xff09;密码验证 2&#xff09;密钥对验证 三、使用 SSH 客户端程序 1.ssh 远…

从 Sora 制作的短片看AI生成视频的优势与局限性解析

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

R语言的基本图形

一&#xff0c;条形图 安装包 install.packages("vcd") 绘制简单的条形图 barplot(c(1,2,4,5,6,3)) 水平条形图 barplot(c(1,2,4,5,6,3),horiz TRUE) 堆砌条形图 > d1<-c("Placebo","Treated") > d2<-c("None",&qu…

聚类分析:使用R语言对Iris数据集进行K均值聚类

引言 聚类分析是一种常用的无监督学习技术&#xff0c;旨在将数据集中的样本分成具有相似特征的组。K均值聚类是其中一种常见的方法&#xff0c;它通过将数据点划分为K个簇&#xff0c;并使每个数据点与其所属簇的中心点距离最小化来实现聚类。本文将介绍如何使用R语言执行K均…

matlab求时间序列的时间滞后相关性

matlab求时间序列的时间滞后相关性 自相关、互相关、加权相关、滞后相关等相关性分析&#xff0c;在时间序列分析中经常被用到&#xff0c;可以量化两个时间序列的相关程度&#xff0c;特别对于有季节性趋势的序列中这个分析尤为必要。下面介绍一个Matlab函数&#xff0c;用于进…

FPGA实现图像处理之【直方图均衡-寄存器版】

FPGA实现直方图统计 一、图像直方图统计原理 直方图的全称为灰度直方图&#xff0c;是对图像每一灰度间隔内像素个数的统计。即对一张图片中每隔二灰度值的像素数量做统计&#xff0c;然后以直方图的形式展现出来。图下的亮暗分布在直方图中就可以一目了然&#xff0c;直方图…

分布式系统事务一致性解决方案(基于事务消息)

参考&#xff1a;https://rocketmq.apache.org/zh/docs/featureBehavior/04transactionmessage/ 文章目录 概要错误的方案方案一&#xff1a;业务方自己实现方案二&#xff1a;RocketMQ 事务消息什么是事务消息事务消息处理流程事务消息生命周期使用限制使用示例使用建议 概要 …

WPF —— MVVM 指令执行不同的任务实例

标签页 设置两个按钮&#xff0c; <Button Content"修改状态" Width"100" Height"40" Background"red"Click"Button_Click"></Button><Button Content"测试"Width"100"Height"40&…

java案例-读取xml文件

需求 导入依赖 <dependencies><!-- dom4j --><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency> </dependencies>代码 SAXReader saxReade…

BERT一个蛋白质-季军-英特尔创新大师杯冷冻电镜蛋白质结构建模大赛-paipai

关联比赛: “创新大师杯”冷冻电镜蛋白质结构建模大赛 解决方案 团队介绍 paipai队、取自 PAIN AI&#xff0c;核心成员如我本人IvanaXu(IvanaXu GitHub)&#xff0c;从事于金融科技业&#xff0c;面向银行信用贷款的风控、运营场景。但我们团队先后打过很多比赛&#xf…

Vue后台系统demo小计

创建项目 1.报错 Error: command failed: npm install --loglevel error --legacy-peer-deps 措施1&#xff1a;node.js文件夹属性 》高级 》选择第一个允许 Users(XXX\Users) &#xff08;对我无用&#xff09; 措施2&#xff1a;PowerShell(以管理员身份运行) 》 cd 想存…

C++ | Leetcode C++题解之第55题跳跃游戏

题目&#xff1a; 题解&#xff1a; class Solution { public:bool canJump(vector<int>& nums) {int n nums.size();int rightmost 0;for (int i 0; i < n; i) {if (i < rightmost) {rightmost max(rightmost, i nums[i]);if (rightmost > n - 1) {r…

【Leetcode每日一题】 动态规划 - 简单多状态 dp 问题 - 打家劫舍 II(难度⭐⭐)(67)

1. 题目解析 题目链接&#xff1a;213. 打家劫舍 II 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 这个问题是经典的“打家劫舍”问题的变种&#xff0c;原问题是在单排房屋中进行偷窃&#xff0c;而这个问题则是在…

利用Triple U.Net结构对冷冻切片HE染色组织学图像进行核实例分割

利用Triple U.Net结构对冷冻切片H&E染色组织学图像进行核实例分割 摘要IntroductionRelated WorksDatasetProposed MethodologyDataset PreparationSegmentation BranchLoss FunctionWatershed Algorithm Nuclei Instance Segmentation of Cryosectioned H&E Stained H…

JavaScript全套检验系统(LIS)源码C# + MVC + SQLserver + Redis 云LIS系统源码 区域医疗云LIS系统源码

JavaScript全套检验系统&#xff08;LIS&#xff09;源码C# MVC SQLserver Redis 云LIS系统源码 区域医疗云LIS系统源码 实验室信息系统&#xff08;Laboratory Information System&#xff0c;缩写LIS&#xff09;是一类用来处理实验室过程信息的软件。这套系统通常与其他信…

ArcGIS基础:便捷分享图层包和地图包

1、分享图层包&#xff1a; 首先&#xff0c;选中要分享的数据&#xff0c;右键创建图层包&#xff0c;修改保存路径。 找到项目描述那一栏&#xff0c;将摘要、标签、描述都填写分享图层包的相关内容。 一切设置好之后&#xff0c;点击右上角的【分析】按钮。 点击分析之后…

vue2集成ElementUI编写登录页面

目录 1. 整理目录文件&#xff1a; a. app.vue文件如下&#xff1a; b. Login.vue文件如下&#xff1a; c. router/index.js文件如下&#xff1a; d. 删除components中的文件&#xff1a; e. 最终项目目录整理如下&#xff1a; 2. 集成ElementUI编写登录页面 a. 安装El…

MCU自动测量单元:自动化数据采集的未来

随着科技的飞速发展&#xff0c;自动化技术在各个领域中的应用日益广泛。其中&#xff0c;MCU(微控制器)自动测量单元以其高效、精准的特性&#xff0c;成为自动化数据采集领域的佼佼者&#xff0c;引领着未来数据采集技术的革新。本文将深入探讨MCU自动测量单元的原理、优势以…