关于 UUID 生成器
在浏览器中生成 UUID v1、v3、v4、v5、v6、v7,适合随机 ID、稳定命名空间 ID、可排序 ID 与开发测试场景。
常见用途
- 生成随机或可排序 ID
- 生成基于命名空间的稳定 UUID
- 准备演示数据、测试 fixture 和占位标识
使用步骤
- 先选择适合场景的 UUID 版本。
- 按需设置数量,以及命名空间和名称。
- 生成后查看、复制或下载整批结果。
UUID 里到底存了什么
UUID 是 128 位,通常写成 8-4-4-4-12 的 32 个十六进制字符。这些位并不是全部自由:其中 4 位表示版本,2 到 3 位表示变体,用来标记 RFC 4122 及其后继 RFC 9562 定义的布局。在 v4 里,真正随机的只有 122 位。版本号可以直接从字符串读出来——第三组的第一个字符就是版本号,所以 3f2a91c4-8b0e-4d17-9f3a-6c1de52b7a90 是 v4,而第四组开头的 9 表示标准变体。除此之外的部分才是随机内容。
各版本该怎么选
v4 是纯随机,只要你需要的是「一个不会重复的值」,它就是正确的默认选项。v1 和 v6 会嵌入时间戳和节点标识(历史上是 MAC 地址),因此会泄露生成机器和生成时刻。v3 和 v5 是「命名空间 + 名称」的确定性哈希,同样的输入永远得到同样的 UUID;v5 用 SHA-1,比基于 MD5 的 v3 更值得选。v7 把 Unix 毫秒时间戳放在高位,其余填随机。如果这个标识要进数据库索引,v7 通常是更好的默认值。
v7 为什么可排序,以及这为什么重要
随机标识是散开的。用 v4 当主键时,每次插入都落在 B 树的任意位置,数据库要反复分裂页面、把脏块散布到整个索引,而不是顺着末尾追加。在大表上这会表现为写放大和缓冲池命中率下降。v7 把 48 位毫秒时间戳放在最前面,新生成的值排序上就在旧值之后,插入始终集中在索引右端。你既保留了不需要协调的全局唯一性,又拿回了自增主键本来免费提供的插入局部性。
碰撞概率的实际数字
122 位随机意味着 v4 的取值空间约为 5.3 x 10^36。按生日界估算,要达到 50% 的碰撞概率大约需要 2.7 x 10^18 个 UUID——相当于每秒生成十亿个、连续生成 85 年。换成更现实的规模:即使生成一万亿个(远超绝大多数系统一生的量),出现任何一次碰撞的概率仍在千万分之一量级。所以正确生成的 v4 不需要做唯一性校验。真正的风险不是数学,而是随机源太弱:用 Math.random()、带种子的伪随机数、或初始化不良的嵌入式设备生成的值,格式看着没问题,却可能重复。
存储、格式与比较
标准文本形式是 36 个字符(32 个十六进制字符加 4 个连字符),习惯用小写,但解析时应当兼容大写。它的本体只有 16 字节,所以 PostgreSQL 的原生 uuid 列或 MySQL 的 BINARY(16),占用空间不到 CHAR(36) 的一半,比较也更快。有些系统会加 urn:uuid: 前缀或用花括号包起来,那仍然是同样的 128 位。由于不同来源的大小写和连字符习惯不一致,应该在入口处先归一化,而不是直接比字符串——否则同一个标识从两个服务传来,会被当成两条不同记录。
什么时候不该用 UUID
UUID 是标识符,不是密钥。v4 在实践中确实猜不出来,但把它当成访问凭证意味着:任何看到这个 URL、日志行或 Referer 头的人都拿到了钥匙,而且永不过期。这种场景应该用有作用域、有有效期的真正 token。v1 和 v6 用在对外场景更糟,因为内嵌的时间戳和节点标识会暴露生成的时间和位置。UUID 也不适合直接给用户看:没有人愿意在电话里念 36 个字符,订单号或短码通常更适合对外,UUID 留在内部即可。