UUID在Java中的实现与应用
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中的实现与应用的更多相关文章
- 什么是uuid以及uuid在java中的使用
什么是UUID?UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符.UUID具有以下涵义: 经由一定的算法机 ...
- Java中的随机数生成器:Random,ThreadLocalRandom,SecureRandom
Java中的随机数生成器:Random,ThreadLocalRandom,SecureRandom 文中的 Random即:java.util.Random,ThreadLocalRandom 即: ...
- Java中Comparable和Comparator你知多少?
前言: 我喜欢这种遨游在Java的世界里,精心研究学习新鲜事物的感觉,即便再小再细再微不足道的东西,也让我乐此不疲,同时我也更愿意将我所会的东西分享出来供大家学习以及方便自己日后回顾.好了,闲话不多说 ...
- Java基础学习(五)-- Java中常用的工具类、枚举、Java中的单例模式之详解
Java中的常用类 1.Math : 位于java.lang包中 (1)Math.PI:返回一个最接近圆周率的 (2)Math.abs(-10):返回一个数的绝对值 (3)Math.cbrt(27): ...
- java中并发下的集合类
java中常见的集合类大部分是非线程安全的,在多线程情况下会报并发修改异常(ConcurrentModificationException) 并发下的ArrayList类: //集合类不安全的例子 p ...
- 工具篇-Java中一些utils
下边是整理的一些Java开发的utils,顺便吐槽下新浪博客的编辑器排版跟我写的博客一样 烂,所以改用博客园 一.字符串 1. Java中String与其他类型之间的转换 String与日期对象 pu ...
- FFmpeg在JAVA中的使用-音频提取&字幕压缩
由于项目需求中涉及到视频中音频提取,以及字幕压缩的功能,一直在研究ffmpeg,仅仅两个功能,却深受ffmpeg的折磨. 今天谈谈ffmpeg在java中的简单使用,首先下载FFmpeg包,官方地址: ...
- java中调用kettle转换文件
java中调用kettle转换文件 通过命令行也能够调用,然后java中调用命令行代码也能够.这样没有和java代码逻辑无缝集成.本文说明kettle5.1中假设通过其它API和java代码无缝集成: ...
- 多线程编程学习六(Java 中的阻塞队列).
介绍 阻塞队列(BlockingQueue)是指当队列满时,队列会阻塞插入元素的线程,直到队列不满:当队列空时,队列会阻塞获得元素的线程,直到队列变非空.阻塞队列就是生产者用来存放元素.消费者用来获取 ...
随机推荐
- Shell 字符截取命令 awk
awk命令# awk '条件1{动作1} 条件2{动作2}….' 文件名一般使用关系表达式作为条件动作:1.格式化输出 2.流程控制语句 处理cut命令无法截取空格的列 例子:截取出磁盘使用率 df ...
- linux中文件的时间戳
touch命令 touch用来创建新文件,或者修改时间戳. linux中的文件有三个时间点,利用stat命令查看: 1.atime:最后访问时间:文件最后一次被存取或执行的时间. 2.mtime:最后 ...
- Android如何在一个TextView中实现多种文本风格?
本文选自StackOverflow(简称:SOF)精选问答汇总系列文章之一,本系列文章将为读者分享国外最优质的精彩问与答,供读者学习和了解国外最新技术,本文为大家讲解Android中,如何在一个 ...
- 压缩JS,CSS的工具
目标: 压缩项目中的JS,CSS文件. 方法一:使用uglifyjs uglifycss 压缩JS: 1.安装NODEJS.是一个在服务端运行的JS语言.下载地址https://nodejs.org/ ...
- cf1088E Ehab and a component choosing problem (树形dp)
题意(考试时看错了对着样例wa了好久..):从树上选k个连通块,使得权值的平均值最大的基础上,选的块数最多 如果不考虑块数最多的限制,肯定是只选一个权值最大的块是最好的 然后只要看这个权值最大的块有多 ...
- 20165223《Java程序设计》第八周Java学习总结
教材学习内容总结 第12章-JAVA多线程机制 要点 Java中的线程 Thread类与线程的创建 线程的常用方法 线程同步 协调同步的线程 线程联合 GUI线程 计时器线程 教材学习中的问题和解决过 ...
- ACM-ICPC 2018 南京赛区网络预赛 L题(分层最短路)
题目链接:https://nanti.jisuanke.com/t/31001 题目大意:给出一个含有n个点m条边的带权有向图,求1号顶点到n号顶点的最短路,可以使<=k条任意边的权值变为0. ...
- python学习day5 数据类型Ⅲ(字典)
day5 字典 回顾&补充 面试题 #数据类型判断a = 1 #intb = (1) #intc = ('1') #strd = (1,) #tuple int py2/py3 除法 强制转换 ...
- JAVA多线程之volatile 与 synchronized 的比较
一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空 ...
- Nginx简易编译安装
1.下载Nginx: http://nginx.org/download/nginx-1.6.3.tar.gz 2.安装Pcre.Zlib.Openssl等相关组件: [root@track ngin ...