• UUID简记


    一、概述

    wiki上的解释:

    universally unique identifier (UUID) is a 128-bit number used to identify information in computer systems.

    128位的UUID也并非没有重复的可能,理论证明这个重复的概率很小近乎为零以至于可以忽略。

    UUID规范的表示格式通常用32个16进制字符表示(也就是"0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" /"a" / "b" / "c" / "d" / "e" / "f"这16个字符)。

    这32个字符通常被连字符“-”分成5个组(简记为8-4-4-4-12格式),如下:

    8a2986cc-256d-470b-bc3d-027113f76553

    5个组所表示的含义如下表所示(图表来自wiki):

    UUID record layout
    NameLength (bytes)Length (hex digits)Contents
    time_low 4 8 integer giving the low 32 bits of the time
    time_mid 2 4 integer giving the middle 16 bits of the time
    time_hi_and_version 2 4 4-bit "version" in the most significant bits, followed by the high 12 bits of the time
    clock_seq_hi_and_res clock_seq_low 2 4 1-3 bit "variant" in the most significant bits, followed by the 13-15 bit clock sequence
    node 6 12 the 48-bit node id

    其中version代表了UUID按照何种规则产生。UUID有四种版本:

    1、Time-based UUID

    2、DCE security UUID

    3、Name-based UUID

    4、Randomly generated UUID

    Version 1 UUIDs are generated from a time and a node id (usually the MAC address); version 2 UUIDs are generated from an identifier (usually a group or user id), time, and a node id; versions 3 and 5 produce deterministic UUIDs generated by hashing a namespace identifier and name; and version 4 UUIDs are generated using a random or pseudo-random number.

    variant(变体,或者更通俗的理解就是类型,type)代表了UUID的位布局。UUID也有四种变体,除了variant 位的不同,variant 1和variant 2的区别在于存储和传输时,variant 1用网络字节序(大端模式),variant 2用本地字节序(小端模式)。

    二、Java中UUID实现

    java中提供了UUID类。在UUID类的内部,将128位分两部分存储:最低有效位(64位)leastSigBits和最高有效位(64位)mostSigBits

    其文档中对这两部分的位布局做了简单说明,但是这里好像与wiki上面的有点出入,按照wiki的说法,这里应该是variant 1而不是variant 2,并且在randomUUID()中重置variant位时也是重置了2个bit位:10xx,总之这里关注重点即可。

     * <p>The layout of a variant 2 (Leach-Salz) UUID is as follows:
     *
     * The most significant long consists of the following unsigned fields:
     * <pre>
     * 0xFFFFFFFF00000000 time_low
     * 0x00000000FFFF0000 time_mid
     * 0x000000000000F000 version
     * 0x0000000000000FFF time_hi
     * </pre>
     * The least significant long consists of the following unsigned fields:
     * <pre>
     * 0xC000000000000000 variant
     * 0x3FFF000000000000 clock_seq
     * 0x0000FFFFFFFFFFFF node
     * </pre>

    UUID通过静态工厂方法产生伪随机的UUID,生成UUID实例的步骤大致如下:

    1、产生长度为16的伪随机字节数组

    2、重置version位和variant位,4bit的version位重置为0100,2bit的variant位重置为10xx。

    3、调用私有构造器UUID(byte[] data),将步骤2中的随机字节数组的前8字节给mostSigBits,后8字节给leastSigBits,至此,一个UUID实例产生。

        public static UUID randomUUID() {
            SecureRandom ng = numberGenerator;
            if (ng == null) {
                numberGenerator = ng = new SecureRandom();
            }
    
            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);
        }
        private UUID(byte[] data) {
            long msb = 0;
            long lsb = 0;
            assert data.length == 16;
            for (int i=0; i<8; i++)
                msb = (msb << 8) | (data[i] & 0xff);
            for (int i=8; i<16; i++)
                lsb = (lsb << 8) | (data[i] & 0xff);
            this.mostSigBits = msb;
            this.leastSigBits = lsb;
        }

    用法如下:

                UUID uuid = UUID.randomUUID();
                System.out.println(uuid.toString());//f2fbeb3c-07e0-41e2-8dd2-1a49e77d6d67
                System.out.println(Long.toHexString(uuid.getMostSignificantBits()));//f2fbeb3c07e041e2
                System.out.println(Long.toHexString(uuid.getLeastSignificantBits()));//8dd21a49e77d6d67

    也可以产生version 3的UUID,以传入的字节数组name为参数,通过MD5算法生成长度为16的字节数组,之后的处理过程与上面的类似。

        public static UUID nameUUIDFromBytes(byte[] name) {
            MessageDigest md;
            try {
                md = MessageDigest.getInstance("MD5");
            } catch (NoSuchAlgorithmException nsae) {
                throw new InternalError("MD5 not supported");
            }
            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);
        }

    用法如下:

                UUID uuid = UUID.nameUUIDFromBytes("2018".getBytes());
                System.out.println(uuid.toString());//84ddfb34-126f-33a4-8ee3-8d7044e87276

    三、MySQL中的UUID

     MySQL中提供了UUID()函数来获取UUID,必要的情况下可以方便地以此充当表的主键。此外,UUID_SHORT()函数返回一个64位的无符号数字。

    四、参考资料

    1、https://en.wikipedia.org/wiki/Universally_unique_identifier

    2、https://tools.ietf.org/html/rfc4122#section-4.1

    3、https://dev.mysql.com/doc/refman/5.5/en/miscellaneous-functions.html#function_uuid

    4、JDK1.6 src

    
    
  • 相关阅读:
    数据库02
    MySQL1
    GIL 死锁 递归锁 event 信号量 线程Queue
    小脚本 暴力删除文件 刷屏
    常见web攻击 及基础 回顾(杂记)
    接口中的简单异步 async
    python协程 示例
    python 利用jinja2模板生成html
    python 调用webservices 接口
    python 进程 进程池 进程间通信
  • 原文地址:https://www.cnblogs.com/qcblog/p/8450428.html
Copyright © 2020-2023  润新知