什么是UUID

UUID 是指(Universally Unique Identifier)通用唯一识别码,128位。RFC 4122描述了具体的规范实现。

现实问题

我们开发的时候,数据库表总会有一个主键,以前我们可能会使用自增的数字作为主键。这样做去确实查询的时候比较快, 但是在做系统集成或者数据迁移的的时候就麻烦了。这是id就有可能重复了。那么有什么比较好的方法解决这一问题呢? 于是jdk1.5出了UUID这个类来生成唯一的字符串标识。

UUID作用

UUID 的目的是让分布式系统中的所有元素都能有唯一的识别信息。如此一来,每个人都可以创建不与其它人冲突的 UUID,就不需考虑数据库创建时的名称重复问题。其作用视场景而定。

目前最广泛应用的 UUID,即是微软的 Microsoft's Globally Unique Identifiers (GUIDs),而其他重要的应用, 则有 Linux ext2/ext3 档案系统、LUKS 加密分割区、GNOME、KDE、Mac OS X 等等。

UUID定义

UUID使用16进制表示,共有36个字符(32个字母/数字+4个连接符"-")组成,格式为8-4-4-4-12 ;【一个字母/数字只代表4个bit,所以是(8+4+4+4+12)*4=128位;】

由一组32个16进制数码(0-9a-z)所构成,故 UUID 理论上的总数为,约等于

也就是说若每纳秒产生1百万个 UUID,要花100亿年才会将所有 UUID 用完。

格式:

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

示例:

96b31816-ae1c-11ed-904f-4531ee40a9e3

格式中M和N都有具体的含义

数字 M的四位表示 UUID 版本,当前规范有5个版本,M可选值为1, 2, 3, 4, 5 ;

数字 N的一至四个最高有效位表示 UUID 变体( variant ),有固定的两位10xx因此只可能取值8, 9, a, b。

这5个版本使用不同算法,利用不同的信息来产生UUID,各版本有各自优势,适用于不同情景。具体使用的信息

版本 1:UUID 是根据时间和 MAC 地址生成的;

版本 2:UUID 是根据标识符(通常是组或用户 ID)、时间和节点 ID生成的;

版本 3:UUID 是通过散列(MD5 作为散列算法)名字空间(namespace)标识符和名称生成的;

版本 4:UUID 使用随机性或伪随机性生成;

版本 5:类似于版本 3(SHA1 作为散列算法)。

故UUID每个版本不是根据精度区分的,Version5并不会比Version1精度高,在精度上,大家都能保证唯一性,重复的概率近乎于0。

为了能兼容过去的 UUID,以及应对未来的变化,因此有了变体(Variants)这一概念。

目前已知的变体有下面 4 种:

变体 0:格式为 0xxx,为了向后兼容预留。

变体 1:格式为 10xx,当前正在使用的。

变体 2:格式为 11xx,为早期微软的 GUID 预留。

变体 3:格式为 111x,为将来的扩展预留,目前暂未使用。

在上例中,M 是 1,N 是 a(二进制为 1010,符合 10xx 的格式),这就意味着这个 UUID 是“版本 1”、“变体 1”的 UUID。

目前大多数使用的 UUID 大都是变体 1,N 的取值是 8、9、a、b 中的一个。

version 1——date-time & MAC address

基于时间戳及MAC地址的UUID实现。它包括了48位的MAC地址和60位的时间戳,

v1为了保证唯一性,当时间精度不够时,会使用13~14位的clock sequence来扩展时间戳,比如:

当UUID的生产成速率太快,超过了系统时间的精度。时间戳的低位部分会每增加一个UUID就+1的操作来模拟更高精度的时间戳,换句话说,就是当系统时间精度无会区分2个UUID的时间先后时,为了保证唯一性,会在其中一个UUID上+1。所以UUID重复的概率几乎为0,时间戳加扩展的clock sequence一共有74bits,(2的74次方,约为1.8后面加22个零),即在每个节点下,每秒可产生1630亿不重复的UUID(因为只精确到了秒,不再是74位,所以换算了一下)。

相对于其它版本,v1还加入48位的MAC地址,这依赖于网卡供应商能提供唯一的MAC地址,同时也可能通过它反查到对应的MAC地址。Melissa病毒就是这样做到的。

Version2(date-time Mac address)

这是最神秘的版本,RFC没有提供具体的实现细节,以至于大部分的UUID库都没有实现它,只在特定的场景(DCE security)才会用到。所以绝大数情况,我们也不会碰到它。

Version3,5(namespace name-based)

V3和V5都是通过hash namespace的标识符和名称生成的。V3使用MD5作为hash函数,V5则使用SHA-1。

因为里面没有不确定的部分,所以当namespace与输入参数确定时,得到的UUID都是确定唯一的。

具体的流程就是

把namespace和输入参数拼接在一起,如"http/http://wwwbaidu.com" ++ "/query=uuid";

使用MD5算法对拼接后的字串进行hash,截断为128位;

把UUID的Version和variant字段都替换成固定的;

如果需要to_string,需要转为16进制和加上连接符"-"。

把V3的hash算法由MD5换成SHA-1就成了V5。

Version4(random)

这个版本使用最为广泛:

其中4位代表版本,2-3位代表variant。余下的122-121位都是全部随机的。即有2的122次方(5.3后面36个0)个UUID。一个标准实现的UUID库在生成了2.71万亿个UUID会产生重复UUID的可能性也只有50%的概率:

这相当于每秒产生10亿的UUID,持续85年,而把这些UUID都存入文件,每个UUID占16bytes,总需要45 EB(exabytes),比目前最大的数据库(PB)还要大很多倍。

UUID的重复概率

Java中 UUID 使用版本4进行实现,所以由java.util.UUID类产生的 UUID,128个比特中,有122个比特是随机产生,4个比特标识版本被使用,还有2个标识变体被使用。利用生日悖论,可计算出两笔 UUID 拥有相同值的机率约为

其中x为 UUID 的取值范围,n为 UUID 的个数。

以下是以 x =

计算出n笔 UUID 后产生碰撞的机率:

换句话说,每秒产生10亿笔 UUID ,100年后只产生一次重复的机率是50%。如果地球上每个人都各有6亿笔 UUID,发生一次重复的机率是50%。与被陨石击中的机率比较的话,已知一个人每年被陨石击中的机率估计为170亿分之1,也就是说机率大约是0.00000000006 (6 x ),等同于在一年内生产2000亿个 UUID 并发生一次重复。

Java获取uuid示例

使用 JDK 原生的API

import java.util.UUID;public class Test {public static void main(String[] args) {// JDK 原生的 API 获取UUID// uuid版本3获取uuidUUID uuid3 = UUID.nameUUIDFromBytes("test".getBytes());int version3 = uuid3.version();System.out.println("UUID3:" + uuid3 + " 版本 " + version3);// uuid版本4获取uuidUUID uuid4 = UUID.randomUUID();int version4 = uuid4.version();System.out.println("UUID4:" + uuid4 + " 版本 " + version4);// 生成一个基于指定 UUID 字符串的 UUID 对象UUID uuid = UUID.fromString("098f6bcd-4621-3373-8ade-4e832627b4f6");int version = uuid.version();System.out.println("UUID_fromString:" + uuid + " 版本 " + version);}
}

nameUUIDFromBytes() 会生成一个版本 3 的UUID,不过需要传递一个名称的字节数组作为参数。

randomUUID() 方法生成了一个版本 4 的 UUID,这也是生成 UUID最方便的方法。如果只使用原生 JDK 的话,基本上都用的这种方式。

fromString() 方法会生成一个基于指定 UUID 字符串的 UUID对象,如果指定的 UUID 字符串不符合 UUID 的格式,将抛出 IllegalArgumentException 异常。

使用com.fasterxml.uuid.Generators

除了使用 JDK 原生的 API 之外,还可以使用com.fasterxml.uuid.Generators,需要先在项目中加入该类的 Maven 依赖。

<dependencies>

<dependency>

<groupId>com.fasterxml.uuid</groupId>

<artifactId>java-uuid-generator</artifactId>

<version>3.1.4</version>

</dependency>

</dependencies>

代码:

import com.fasterxml.uuid.Generators;import java.util.UUID;public class Test {public static void main(String[] args) {// JDK 原生的 API 获取UUID// uuid版本1获取uuidUUID uuid1 = Generators.timeBasedGenerator().generate();System.out.println("UUID : " + uuid1);System.out.println("UUID 版本 : " + uuid1.version());// uuid版本4获取uuidUUID uuid2 = Generators.randomBasedGenerator().generate();System.out.println("UUID : " + uuid2);System.out.println("UUID 版本 : " + uuid2.version());}
}

Generators.timeBasedGenerator().generate() 可用于生成版本1 的 UUID,Generators.randomBasedGenerator().generate() 可用于生成版本4 的 UUID。

总结

使用较多的是版本1和版本4,其中版本1使用当前时间戳和MAC地址信息。版本4使用(伪)随机数信息,128bit中,除去版本确定的4bit和variant确定的2bit,其它122bit全部由(伪)随机数信息确定。

因为时间戳和随机数的唯一性,版本1和版本4总是生成唯一的标识符。若希望对给定的一个字符串总是能生成相同的 UUID,使用版本3或版本5。如果只是需要生成一个唯一ID,你可以使用V1或V4。

- V1基于时间戳和Mac地址,这些ID有一定的规律(你给出一个,是有可能被猜出来下一个是多少的),而且会暴露你的Mac地址。

- V4是完全随机(伪)的。

如果对于相同的参数需要输出相同的UUID,你可以使用V3或V5。

- V3基于MD5 hash算法,如果需要考虑与其它系统的兼容性的话,就用它,因为它出来得早,大概率大家都是用它的。

- V5基于SHA-1 hash算法,这个是首选。

UUID简介以及java代码获取UUID示例相关推荐

  1. java 读取流的字符编码格式_如何使用Java代码获取文件、文件流或字符串的编码方式...

    标签: 今天通过网络资源研究了一下如何使用Java代码获取文件.文件流或字符串的编码方式,现将代码与大家分享: package com.ghj.packageoftool; import info.m ...

  2. java获取jndi密码_用JAVA代码获取Weblogic配置的JNDI 数据源连接

    第一步:生成与JDK版本对应的weblogicjar,利用cmd 进入到weblogic_home 路径下进入到server/lib目录,然后运行  JDK  1.6 命令 "java -j ...

  3. java代码获取银行实时汇率

    java代码获取银行实时汇率 因为工作的时候甲方要求实施获取银行汇率,并且他们还不提供免费的接口,我就自己去网上找了接口,并写了实现代码,如果你需要的话直接复制粘贴就可以用了. 我用的是idea开发的 ...

  4. 如何使用java代码获取屏幕显示器个数

    使用java代码获取屏幕显示器个数,主要是使用java中的GraphicsEnvironment对象,关于GraphicsEnvironment对象的介绍,可以去GraphicsEnvironment ...

  5. Android 使用java 代码获取res 里面的value 定义的数组

    现在res value 里面定义了一个array.xml 内容如下 <?xml version="1.0" encoding="utf-8"?> & ...

  6. 在线运行Java代码获取APNIC中国区的ip段,用作绕过国内ip

    如题,不废话了,直接上java代码.这个获取的IP段是最新的国内IP段. import java.io.*; import java.net.HttpURLConnection; import jav ...

  7. java代码获取项路径_Java中获取各种路径的方法盘点

    Java代码中获取路径 假设当前项目路径为:D:/wunian/workspace/JavaProject,现在来分别获取此项目中的各种路径. 1.获取资源文件(.class文件)所在路径(四种方式) ...

  8. Qt使用JNI调用Java代码—————附带完整示例

    文章目录 0 背景 1 调用准备 2 调用 2.1 调用方法 2.2 方法签名 2.3 调用示例 2.4 注意事项 3 完整示例代码 3.1 部分代码 3.2 附赠示例 0 背景 在开发Android ...

  9. uuid获取java_JAVA代码获取UUID

    2.UUID工具类 import java.util.UUID; public class UUIDGenerator { public UUIDGenerator() { } public stat ...

最新文章

  1. 怎么高效的运用金蝶软件
  2. android开发岗_android应用开发
  3. centos找不到环境变量 -bash: ls: command not found(亲测)
  4. 【WebPack】引入Vue;认识Plugin;使用uglifyjs丑化JS代码;搭建本地服务器;生产开发环境配置文件的抽离
  5. 云原生开发框架dapr环境搭建:CLI安装和初始化
  6. 我们的系统检测到您的计算机网络中存在异常流量_如何建立我们的网络防线?入侵检测,确保我们的网络安全...
  7. python ftplib bufsize_python:ftplib模块
  8. 华为Mate 30 Pro全新配色曝光:“赤茶橘”颜值超高
  9. 【Maven】windows 拷贝项目到内网 全面飘红 终极解决
  10. 惠普在安全领域发力 收购大数据加密企业
  11. Win10快捷键模式退出的方法
  12. Ubuntu系统下MRIcroN、FSL6.0.5、Freesurfer7.1.1、ANTs、MRtrix3、AFNI的安装详解——核磁共振数据处理必备
  13. win7修改计算机名 bat,用cmd改计算机名.bat 无需重启电脑生效
  14. python实现视频ai换脸_python 实现 AI 换脸
  15. React的render不是纯函数? triggering nested component updates from render is not allowed
  16. wer 流程图编程_孩子学完各个阶段的编程课能够参加哪些比赛?
  17. 【转】Vmware 8.0注册码 序列号 key 注册方法
  18. php调用原生java程序
  19. Word2vec原理+实战学习笔记(二)
  20. 将汉字转换为拼音或者翻转

热门文章

  1. 手机端微信传动文件,超出文件限制,怎么办?
  2. c语言程序设计常用思维,C语言程序设计中计算思维的思考①
  3. 微信头像存储mysql数据库
  4. 推荐一款简单易用线上引流测试工具:GoReplay
  5. 海量数据搜索、存储、查询、排序算法
  6. 自由职业一时爽,一直自由一直爽
  7. 如何培养青少年的阅读习惯?父母应该从三个方面培养青少年的好兴趣
  8. attention机制、self-attention、channel attention、spatial attention、multi-head attention、transformer
  9. k8s原生的CI/CD工具tekton
  10. 卖货文案不会写?试试这5个方法(二)