浅度解析MongoDB的ObjectID生成规则

ObjectID官方指南

ObjectID是类似与“507f1f77bcf86cd799439011”的24位字符串,占用12字节,生成规则如下:

ObjectId is a 12-byte BSON type, constructed using:
- 4-byte value representing the seconds since the Unix epoch,
- 3-byte machine identifier,
- 2-byte process id, and
- 3-byte counter, starting with a random value.

自定义生成ObjectID

参考MongoDB的ObjectID生成规则,可自定义生成轻量级的惟一码MyUUID,只需占用8字节
其中MyUUID的生成规则如下:

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---------------------------------
|     time      |mid|   inc     |

第0~3字节存放时间,第4字节存放MachineID,第5~7字节存放自增长ID

MyUUID源码

在一般PC机上,1秒可生成十万不重复的MyUUID,在服务器上效率肯定更高,应该能够满足一般应用要求

import java.util.Date;

class MyUUID
{
    private static int _machineID=0;
    private static int _incID=0;

    private static int getMachineID() {
        //复杂些的可以通过主机主板序列号、IP、硬盘序列号等生成机器码,简单起见默认为1
        _machineID+=1;
        return _machineID%127;
    }

    private static int getInc()
    {
        //一般使用Memcached统一维护一个全局自增ID,简单起见默认为1
        _incID+=1;
        return _incID;
    }

    public static long ObjectID() {  
        long v_time = (int) (System.currentTimeMillis() / 1000);
        int v_machine = getMachineID();
        int v_inc = getInc();

        long myUUID=0;
        myUUID=myUUID | v_inc;
        myUUID=myUUID | (v_machine<<24);
        myUUID=myUUID | (v_time<<32);

        return myUUID;
    }

    public static void reverseObjectID(long myUUID) 
    {
        //反向解析myUUID
        int v_inc =(int) myUUID & 0xFFFFFF;//取出最右边3字节(即24bit)的值,每个16进制数存储4bit
        int v_machine=(int) (myUUID >>> 24) & 0xFF;//无符号右移24位,然后取最右边1字节的值
        long v_time=(myUUID >>>32) & 0xFFFFFFFF;//无符号右移32位,然后取四字节的秒数

        System.out.println("v_time="+Long.toHexString(v_time));
        System.out.println("时间为:"+new java.util.Date(v_time*1000));
        System.out.println("v_machine="+v_machine);
        System.out.println("inc="+v_inc);
    }

    public static void main(String[] args) 
    {
        long objectid;
        long id1=0,id2=0;

        //生成100000个MyUUID
        for (int i=0; i<100000; i++)
        {
            objectid=ObjectID();
            System.out.println("MyUUID="+Long.toHexString(objectid));

            if (i==0)
                id1=objectid;
            else if (i==99999)
                id2=objectid;
            else;
        }

        System.out.println("反向解析MyUUID...................");
        reverseObjectID(id1);
        reverseObjectID(id2);
    }
}