定义

UUID是由一个16进制下的32位数所构成,故UUID理论上的总数为1632 =2128,约等于3.4 x 1038。也就是说若每纳秒(ns)产生1万亿个UUID,要花100亿年才会将所有UUID用完。

UUID的标准型式包含32个16进制数字,分为五段,形式为 8-4-4-4-12 的32个字符。示例:

550e8400-e29b-41d4-a716-446655440000

格式

在其规范的文本表示中,UUID 的 16 个 8 位字节表示为 32 个十六进制(基数16)数字,显示在由连字符分隔 ‘-’ 的五个组中,“8-4-4-4-12” 总共 36 个字符(32 个字母数字字符和 4 个连字符)。

例如:

123e4567-e89b-12d3-a456-426655440000
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

M表示 UUID 版本, N的一至三个最高有效位表示 UUID 变体。在例子中,M1Na,这意味着此 UUID 是“变体1”、“版本1”UUID;即基于时间的 DCE/RFC 4122 UUID。

版本由 M 字符串中指示

  • 版本1 - UUID 是根据时间和 节点ID(通常是MAC地址)生成;

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

  • 版本3、版本5 - 确定性UUID 通过散列(hashing)名字空间(namespace)标识符和名称生成;

  • 版本4 - UUID 使用随机性或伪随机性生成。

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

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

版本

V1 时间+MAC地址

版本1的UUID,是根据 60-bit 的时间戳 和 节点(生成UUID的计算机)的 48-bitMAC地址而生成的。

优点:由于在算法中使用了MAC地址,这个版本的UUID可以保证在全球范围的唯一性。

缺点:因为它暴露了电脑的MAC地址和生成这个UUID的时间,这就是这个版本UUID被诟病的地方,使用MAC地址会带来安全性问题。一台机器部署多个实例可能会出现重复。

现在基本没人使用

V2 时间+MAC地址 DCE安全版本

DCE(Distributed Computing Environment)安全的UUID。和基于时间的UUID算法相同,但会把时间戳的前4位置换为POSIX的UID或GID。

不过,在UUID的规范里面没有明确地指定,所以基本上所有的UUID实现都不会实现这个版本。

V3 V5 基于名字空间名称

版本3”和“版本5”的 UUID 被生成散列(hashing)一个名字空间标识符和一个名称。“版本3”使用 MD5 作为散列算法,“版本5”使用 SHA1。

V4 随机UUID

根据随机数,或者伪随机数生成UUID。这种UUID产生有一定的重复概率但是极低,忽略不计;目前使用最多的版本

Java只支持生成版本3和版本4的UUID

V4 随机UUID,UUID.randomUUID().toString()

V4 随机UUID重复概率问题?

V4随机版本有一定的重复概率但是极低,直接上结论,来着维基百科

在 103 万亿 个 版本4 UUID 中找到重复的概率是(十亿分之一)。

UUID缩短长度

原始UUID的是32个字符长度 16进制存储,现在改为64进制存储,即base64,需要22个字符长度。即长度从原始的36降低到22,但是核心没变,只是变了展现形式。

原始的Base64包含+/,其在url中会转义,但是使用url安全的则会自动替换为- _

方式一 org.apache.commons.codec.binary.Base64

	import org.apache.commons.codec.binary.Base64;

    public static String uuidToBase64(String uuidStr) {
        UUID uuid = UUID.fromString(uuidStr);
        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
        bb.putLong(uuid.getMostSignificantBits());
        bb.putLong(uuid.getLeastSignificantBits());
        return Base64.encodeBase64URLSafeString(bb.array());
    }

        public static String uuidFromBase64(String base64) {
        byte[] bytes = Base64.decodeBase64(base64);
        ByteBuffer bb = ByteBuffer.wrap(bytes);
        UUID uuid = new UUID(bb.getLong(), bb.getLong());
        return uuid.toString();
    }

方式二 JDK8 java.util.Base64

	import java.nio.ByteBuffer;
	import java.util.Base64;
	import java.util.UUID;

    private static final Base64.Encoder BASE64_URL_ENCODER = Base64.getUrlEncoder().withoutPadding();
    private static final Base64.Decoder BASE64_URL_DECODER = Base64.getUrlDecoder();

    public static String uuidToBase64(String uuidStr) {
        UUID uuid = UUID.fromString(uuidStr);
        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
        bb.putLong(uuid.getMostSignificantBits());
        bb.putLong(uuid.getLeastSignificantBits());
        return BASE64_URL_ENCODER.encodeToString(bb.array());
    }

    public static String uuidFromBase64(String base64) {
        byte[] bytes = BASE64_URL_DECODER.decode(base64);
        ByteBuffer bb = ByteBuffer.wrap(bytes);
        UUID uuid = new UUID(bb.getLong(), bb.getLong());
        return uuid.toString();
    }

参考:

  • https://zh.wikipedia.org/wiki/%E9%80%9A%E7%94%A8%E5%94%AF%E4%B8%80%E8%AF%86%E5%88%AB%E7%A0%81
  • https://stackoverflow.com/questions/772802/storing-uuid-as-base64-string
Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐