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)是指当队列满时,队列会阻塞插入元素的线程,直到队列不满:当队列空时,队列会阻塞获得元素的线程,直到队列变非空.阻塞队列就是生产者用来存放元素.消费者用来获取 ...
随机推荐
- BZOJ 2521: [Shoi2010]最小生成树(最小割)
题意 对于某一条无向图中的指定边 \((a, b)\) , 求出至少需要多少次操作.可以保证 \((a, b)\) 边在这个无向图的最小生成树中. 一次操作指: 先选择一条图中的边 \((u, v)\ ...
- 【转】RO段、RW段和ZI段 --Image$$??$$Limit 含义(zz)
@2019-02-14 [小记] RO段.RW段和ZI段 --Image$$??$$Limit 含义(zz)
- 队列模式&主题模式
# RabbitMQ 消息中间件 **Advanced Message Queuing Protocol (高级消息队列协议** The Advanced Message Queuing Protoc ...
- surface link
https://www.microsoft.com/zh-cn/software-download/windows10 https://www.ithome.com/html/win10/303197 ...
- iview tree 获取选中子节点的整条数据链
这样子获取到数据是,checked等于true的,获取不到他的父级,父级的父级 解决办法代码如下: //需要有一个唯一ID //==================================== ...
- django 通过邮箱和用户名都能登录
一. 在settings.py 文件中的#Application definition 下增加代码: AUTHENTICATION_BACKENDS=( 'users.views.CustomBack ...
- XTest
腾讯优测是一个移动云测试平台,为应用.游戏.H5混合应用的研发团队提供产品质量检测与问题解决服务. 这是腾讯内部针对微信内的H5,做了一套专门的UI自动化框架.而且都是用真机来跑这些框架,在真机上模拟 ...
- TestNg 11. 超时测试
前沿:多久时间没有响应,就是超时. 代码:用timeOut这个属性,超过规定的时间就是fail,不超过就是success package com.course.testng; import org.t ...
- QT槽函数处理线程
今天用到QTcpSocket的时候,由于客户端发起请求在一个线程里,当readyRead的信号发出后接收的槽函数是否还会在该线程里处理? 现在看来其实是交给主线程处理的,那么我要实现在线程里处理怎么实 ...
- 在gitlab新建空项目,将本地的git仓库的内容上传
gitlab新建了这个项目. 按照官网的步骤上传代码 一:将本地代码上传到本地仓库 1.进入项目文件夹 git init 2.项目代码添加到本地git git add . 3.提交到stage区域 g ...