UUID是什么

UUID的全称为:Universally Unique IDentifier,也被称为GUID(Globally Unique IDentifier)。是一种由算法生成的唯一标识,它实质上是一个128位长的二进制整数。通常表示成32个16进制数组成的字符串,如:21EC2020-3AEA-1069-A2DD-08002B30309D。关于UUID标准的rfc定义详见:http://www.ietf.org/rfc/rfc4122.txt。 当然,GUID一词有时也专指微软对UUID标准的实现,用于Windows操作系统中。

UUID的实现

UUID的格式是这样的:xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx,一共为32个16进制数。

M那个位置,代表版本号,目前UUID的标准实现有5个版本,所以只会是1,2,3,4,5

N那个位置,只会是8,9,a,b

UUID的具体实现存在多个版本,分别为:

1. 基于时间的UUID

基于时间的UUID通过计算当前时间戳、随机数和机器MAC地址得到。由于在算法中使用了MAC地址,这个版本的UUID可以保证在全球范围的唯一性。但与此同时,使用MAC地址会带来安全性问题,这就是这个版本UUID受到批评的地方。如果应用只是在局域网中使用,也可以使用退化的算法,以IP地址来代替MAC地址。

2. DCE(Distributed Computing Environment)安全的UUID

和基于时间的UUID算法相同,但会把时间戳的前4位置换为POSIX的UID或GID,这个版本的UUID在实际中较少用到。

3. 基于名称空间的UUID(MD5)

基于名称的UUID通过计算名称和名称空间的MD5散列值得到,这个版本的UUID保证了:相同名称空间中不同名称生成的UUID的唯一性;不同名称空间中的UUID的唯一性;相同名称空间中相同名称的UUID重复生成是相同的。

4. 基于随机数的UUID

根据随机数,或者伪随机数生成UUID。这种UUID产生重复的概率是可以计算出来的,但随机的东西就像是买彩票:你指望它发财是不可能的,但狗屎运通常会在不经意中到来。可能在测试的时候多线程并发也不见得出现重复,但是却不能保证系统正式上线之后不会出现不重复的UUID,特别是在分布式系统中。

5. 基于名称空间的UUID(SHA1)

和版本3的UUID算法类似,只是散列值计算使用SHA1(Secure Hash Algorithm 1)算法。

在Java中默认实现了基于名称空间的UUID(UUID Version 3)和基于伪随机数的UUID(UUID Version 4),分别为:

/**
* Static factory to retrieve a type 3 (name based) {@code UUID} based on
* the specified byte array.
*
* @param name
* A byte array to be used to construct a {@code UUID}
*
* @return A {@code UUID} generated from the specified array
*/
public static UUID nameUUIDFromBytes(byte[] name) {
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsae) {
throw new InternalError("MD5 not supported", nsae);
}
byte[] md5Bytes = md.digest(name);
md5Bytes[6] &= 0x0f; /* clear version */
md5Bytes[6] |= 0x30; /* set to version 3 */
md5Bytes[8] &= 0x3f; /* clear variant */
md5Bytes[8] |= 0x80; /* set to IETF variant */
return new UUID(md5Bytes);
}
/**
* Static factory to retrieve a type 4 (pseudo randomly generated) UUID.
*
* The {@code UUID} is generated using a cryptographically strong pseudo
* random number generator.
*
* @return A randomly generated {@code UUID}
*/
public static UUID randomUUID() {
SecureRandom ng = Holder.numberGenerator; byte[] randomBytes = new byte[16];
ng.nextBytes(randomBytes);
randomBytes[6] &= 0x0f; /* clear version */
randomBytes[6] |= 0x40; /* set to version 4 */
randomBytes[8] &= 0x3f; /* clear variant */
randomBytes[8] |= 0x80; /* set to IETF variant */
return new UUID(randomBytes);
}

除了Java默认的实现之外,还有一个开源的UUID实现库可以参考:https://github.com/cowtowncoder/java-uuid-generator, 这个库支持实现UUID的V1,V3,V4和V5版本,在需要使用到唯一性ID的地方可以酌情考虑使用。

关于UUID使用的思考和总结

UUID是为了解决标识唯一性而提出的,这在分布式应用场景下非常常见。例如,用户登录Token,数据库记录主键ID等等。但是对于是否可以使用UUID(除了考虑唯一性之外,可能还要考虑有序性),以及使用哪个版本的UUID实现(考虑到效率等因素)需要慎重。例如:虽然UUID可以解决唯一性,但是却不适合直接用于数据库记录主键ID,对于数据库主键ID而言,除了考虑唯一性之外,还要考虑有序性,索引效率等因素。而在用户登录Token标识这种场景下使用UUID是可以的,甚至在使用手机或邮箱作为唯一名称标识的场景下,可以使用基于名称空间的UUID。

通常来讲,如果仅仅需要实现唯一性需求,那么对于使用UUID有如下建议:

  • 对于暴露MAC地址不敏感的场合,使用UUID V1是最佳选择。当然了,也可以通过对UUID进行MD5散列的方式进行保密,不过这需要考虑性能开销。
  • 如果可以保证在指定命名空间内的名称唯一性,例如手机号或者邮箱,那么选择UUID V3或者V5的实现也能保证唯一性。
  • 对于UUID V4,如果是基于伪随机数的实现,是存在出现重复UUID的概率的,如果对于ID唯一性要求不是十分严格的场景,这个版本的实现也可以考虑。

另外,在各个语言平台对应UUID实现的支持各不相同。

1.Java语言

默认只支持V3和V4(基于伪随机数)两种版本的实现

2.Python语言

支持V1,V3,V4,V5版本的UUID实现

Python的UUID V1基于时间戳和MAC地址,最后12个16进制字符就是网卡地址。

>>> import uuid
>>> uuid.uuid1()
UUID('d3a173de-0ca9-11e8-af24-f0d5bf9aedc1')
>>> uuid.uuid1()
UUID('73e4ac9e-0caa-11e8-aa82-f0d5bf9aedc1')

Python支持UUID V3实现,对名称空间内的字符串进行MD5散列值生成UUID。

>>> uuid.uuid3(uuid.NAMESPACE_DNS,"chench")
UUID('a0fda26d-acf1-37da-ad64-7cac7753de92')
>>> uuid.uuid3(uuid.NAMESPACE_DNS,"chench")
UUID('a0fda26d-acf1-37da-ad64-7cac7753de92')

Python的UUID V4实现基于伪随机数实现,这种UUID产生重复的概率是可以计算出来的。

>>> uuid.uuid4()
UUID('d1437e20-95eb-446a-b9ca-9184013b8542')
>>> uuid.uuid4()
UUID('4dce6000-0ad5-4f35-84d8-6b434205d212')

与UUID V3的算法一致,不同的是UUID V5的散列算法为SHA1。

>>> uuid.uuid5(uuid.NAMESPACE_DNS,"chench")
UUID('b8643db9-49d8-5a98-842d-14f3215f08cb')
>>> uuid.uuid5(uuid.NAMESPACE_DNS,"chench")
UUID('b8643db9-49d8-5a98-842d-14f3215f08cb')

【参考】

https://zh.wikipedia.org/wiki/通用唯一识别码 UUID

https://zh.wikipedia.org/wiki/全局唯一标识符 GUID

https://www.jianshu.com/p/d77f3ef0868a 关于UUID的二三事

https://qtdebug.com/java-duplicate-uuid/ 测试 Java 生成 UUID 是否重复

http://www.infoq.com/cn/articles/talk-about-the-history-of-uuid UUID简史

UUID在Java中的实现与应用的更多相关文章

  1. 什么是uuid以及uuid在java中的使用

    什么是UUID?UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符.UUID具有以下涵义: 经由一定的算法机 ...

  2. Java中的随机数生成器:Random,ThreadLocalRandom,SecureRandom

    Java中的随机数生成器:Random,ThreadLocalRandom,SecureRandom 文中的 Random即:java.util.Random,ThreadLocalRandom 即: ...

  3. Java中Comparable和Comparator你知多少?

    前言: 我喜欢这种遨游在Java的世界里,精心研究学习新鲜事物的感觉,即便再小再细再微不足道的东西,也让我乐此不疲,同时我也更愿意将我所会的东西分享出来供大家学习以及方便自己日后回顾.好了,闲话不多说 ...

  4. Java基础学习(五)-- Java中常用的工具类、枚举、Java中的单例模式之详解

    Java中的常用类 1.Math : 位于java.lang包中 (1)Math.PI:返回一个最接近圆周率的 (2)Math.abs(-10):返回一个数的绝对值 (3)Math.cbrt(27): ...

  5. java中并发下的集合类

    java中常见的集合类大部分是非线程安全的,在多线程情况下会报并发修改异常(ConcurrentModificationException) 并发下的ArrayList类: //集合类不安全的例子 p ...

  6. 工具篇-Java中一些utils

    下边是整理的一些Java开发的utils,顺便吐槽下新浪博客的编辑器排版跟我写的博客一样 烂,所以改用博客园 一.字符串 1. Java中String与其他类型之间的转换 String与日期对象 pu ...

  7. FFmpeg在JAVA中的使用-音频提取&字幕压缩

    由于项目需求中涉及到视频中音频提取,以及字幕压缩的功能,一直在研究ffmpeg,仅仅两个功能,却深受ffmpeg的折磨. 今天谈谈ffmpeg在java中的简单使用,首先下载FFmpeg包,官方地址: ...

  8. java中调用kettle转换文件

    java中调用kettle转换文件 通过命令行也能够调用,然后java中调用命令行代码也能够.这样没有和java代码逻辑无缝集成.本文说明kettle5.1中假设通过其它API和java代码无缝集成: ...

  9. 多线程编程学习六(Java 中的阻塞队列).

    介绍 阻塞队列(BlockingQueue)是指当队列满时,队列会阻塞插入元素的线程,直到队列不满:当队列空时,队列会阻塞获得元素的线程,直到队列变非空.阻塞队列就是生产者用来存放元素.消费者用来获取 ...

随机推荐

  1. Hdoj 2108.Shape of HDU 题解

    Problem Description 话说上回讲到海东集团推选老总的事情,最终的结果是XHD以微弱优势当选,从此以后,"徐队"的称呼逐渐被"徐总"所取代,海东 ...

  2. Java 枚举 的学习

    在JDK5.0之后,引进了一种与C语言相通的枚举类型. 所谓枚举类型就是指含有一组具有固定值, 并且容量有限的数据集合. 例如,定义一个星期的枚举类型, 从周一到周日是具有固定大小和固定值的集合 pu ...

  3. android json 解析简单实例

    Android JSON解析跟JAVA 的JSON解析原理是一样的. Android自带的JSON方式跟方便,不需要导包啥的.不深究原理了,直接上代码: public class JsonActivi ...

  4. 【CF981F】Round Marriage(二分答案,二分图匹配,Hall定理)

    [CF981F]Round Marriage(二分答案,二分图匹配,Hall定理) 题面 CF 洛谷 题解 很明显需要二分. 二分之后考虑如果判定是否存在完备匹配,考虑\(Hall\)定理. 那么如果 ...

  5. 【BZOJ5289】[HNOI2018]排列(贪心)

    [BZOJ5289][HNOI2018]排列(贪心) 题面 BZOJ 洛谷 题解 这个限制看起来不知道在干什么,其实就是找到所有排列\(p\)中,\(p_k=x\),那么\(k<j\),其中\( ...

  6. 原生JS节点操作

    获取子节点 1. children 不是标准的dom属性,但是几乎被所有浏览器支持.获取子元素的元素节点(只包括元素节点) 注意:在IE中,children包含注释节点. 2. childNodes ...

  7. X-PACK详解

    启用和禁用启用和禁用X-Pack功能默认情况下,所有X-Pack功能都被启用.您可以启用或禁用特定的X-Pack功能elasticsearch.yml,kibana.yml以及logstash.yml ...

  8. SpringBoot学习笔记(6) SpringBoot数据缓存Cache [Guava和Redis实现]

    https://blog.csdn.net/a67474506/article/details/52608855 Spring定义了org.springframework.cache.CacheMan ...

  9. MVC aspx

    客户端服务器---Model(模型)---View(视图)---Control(控制器) 1.ASP.NET  MVC 2.新建项目引擎选aspx.在Controllers创建控制器,默认启动Home ...

  10. Vue+Django2.0 restframework打造前后端分离的生鲜电商项目(3)

    1.drf前期准备 1.django-rest-framework官方文档 https://www.django-rest-framework.org/ #直接百度找到的djangorestframe ...