uuid,全称Universally Unique IDentifier,是一种id生成方式,我们使用它来生成一唯一的id. 同时,它也被称为guid. uuid有若干生成方法,本文介绍的是一种基于时间的方法(也就是version 1).协议是rfc4122. 在java中,它是系统内置的class.而在c++中,我们想要实现,其实也不困难.
如rfc4122中所示,uuid是一个长为128bit的结构如下的一串数字.
_0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | time_low | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | time_mid | time_hi_and_version | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |clk_seq_hi_res | clk_seq_low | node (0-1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | node (2-5) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
其中time是指UTC 1582年10月15日00:00:00 开始到如今的,以100纳秒为单位的时间数,它是一个60bit长的一个值,所以被存到了几段地方.
clk_seq按情况而定,若可以读状态,那么clk_seq是上个状态的clk_seq+1,否则是随机出来的一个0x3FFF范围中的数字.
node是自定义的一个顺序.
然后一路拼接,得到两个uint64_t类型的数据.输出结果若用string表示,格式应该是这样的:
UUID = time-low "-" time-mid "-" time-high-and-version "-" clock-seq-and-reserved clock-seq-low "-" node time-low = 4hexOctet time-mid = 2hexOctet time-high-and-version = 2hexOctet clock-seq-and-reserved = hexOctet clock-seq-low = hexOctet node = 6hexOctet hexOctet = hexDigit hexDigit hexDigit = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / "a" / "b" / "c" / "d" / "e" / "f" / "A" / "B" / "C" / "D" / "E" / "F"
一个简单例子如下:
f81d4fae-7dec-11d0-a765-00a0c91e6bf6
rfc4122给了个官方实现示例,我也写了个c++版本的简易生成器,里面有些代码还是值得商榷的,比如clk_seq我是直接random的.其实应该检查状态的.代码在osx和centos 64上都编译没有问题.
在java/scala中,若要读取uuid,一般我用fromString.
scala> java.util.UUID.fromString("f81d4fae-7dec-11d0-a765-00a0c91e6bf6") res0: java.util.UUID = f81d4fae-7dec-11d0-a765-00a0c91e6bf6
需要注意的是,uuid中的timestamp和普通的java.util.date中的timestamp单位是不一样的,我们已经说过,uuid中是UTC 1582年10月15日00:00:00至今的100纳秒数,而date中的是UTC1970年1月1日00:00:00至今的毫秒数.我们从uuid中获取ts方法应该是这样的:
scala> val uuid = java.util.UUID.fromString("f81d4fae-7dec-11d0-a765-00a0c91e6bf6") uuid: java.util.UUID = f81d4fae-7dec-11d0-a765-00a0c91e6bf6 scala> val ts = uuid.timestamp ts: Long = 130742845922168750 scala> val ts4j = ( ts - 0x01b21dd213814000L ) / 10000 ts4j: Long = 854991792216 scala> val jdate = new java.util.Date(ts4j) jdate: java.util.Date = Mon Feb 03 12:43:12 EST 1997