UUID簡記

1、概述

wiki上的解釋:html

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

128位的UUID也並不是沒有重複的可能,理論證實這個重複的機率很小近乎爲零以致於能夠忽略。node

UUID規範的表示格式一般用32個16進制字符表示(也就是"0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" /"a" / "b" / "c" / "d" / "e" / "f"這16個字符)。mysql

這32個字符一般被連字符「-」分紅5個組(簡記爲8-4-4-4-12格式),以下:git

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

5個組所表示的含義以下表所示(圖表來自wiki):算法

UUID record layout
Name Length (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有四種版本:sql

一、Time-based UUID數組

二、DCE security UUID網絡

三、Name-based UUIDdom

四、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用本地字節序(小端模式)。

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實例的步驟大體以下:

一、產生長度爲16的僞隨機字節數組

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

三、調用私有構造器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

3、MySQL中的UUID

 MySQL中提供了UUID()函數來獲取UUID,必要的狀況下能夠方便地以此充當表的主鍵。此外,UUID_SHORT()函數返回一個64位的無符號數字。

4、參考資料

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

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

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

四、JDK1.6 src

相關文章
相關標籤/搜索