UUID 生成完全指南:v4、v7、碰撞与误用
需要给订单、文件、微服务消息一个「别撞车」的 ID 时,人们常随手生成 UUID。选 v4 还是 v7、会不会重复、能不能当 API 密钥,却经常混为一谈。本指南按标识符用途拆开随机性、有序性与安全边界,并对照 WebUtils 本地生成器的真实选项操作。
核心一句话
UUID 解决的是「谁唯一」,不是「谁保密」;v4 偏纯随机,v7/ULID 带时间有序利于索引,但都不应替代密码或签名令牌。
在 UUID/ULID 生成器 可选类型、大小写/去连字符与批量数量(1~1000)。
1. 三种类型分别适合什么
工具提供三类(实现使用 crypto.getRandomValues 等浏览器能力):
| 类型 | 结构要点 | 优点 | 代价 / 注意 |
|---|---|---|---|
| UUID v4 | 128 位,版本与变体位固定,其余随机 | 不泄露生成时间,实现简单 | 作主键时随机插入可能加剧 B-Tree 页分裂 |
| UUID v7 | 前缀含毫秒时间,其余随机,版本号为 7 | 大致时间有序,利于写入与按时间粗排 | 可从 ID 推断生成时刻量级 |
| ULID | 128 位语义,Crockford Base32,常 26 字符 | 短、可排序、URL 较友好 | 编码与 UUID 文本形态不同;大小写策略按选项 |
不要把「看起来像 UUID」的字符串都当成同一版本:第 13 个十六进制半字节(去掉连字符后的版本半字节)区分 v4/v7 等;业务校验时应显式约定版本。
2. 碰撞:理论与工程
v4 有效随机位约 122 位量级。生日悖论下,要到天文量级的生成量,碰撞概率才变得值得焦虑。对绝大多数互联网业务:
- 应用层仍建议在数据库对 ID 列加唯一约束——防御的是实现 bug、错误导入、多套生成器不一致,不只是数学碰撞。
- 同一毫秒海量 v7 仍靠随机段区分;不要取消唯一索引「因为大概不会撞」。
- 分布式多机各自用密码学随机源即可;不必中心发号,除非你有业务序号需求。
碰撞极罕见 ≠ 可以当密钥。攻击者猜的是可预测与熵是否够当秘密,不是等生日碰撞。
3. 非安全令牌:最常见的误用
| 误用 | 为何危险 | 更合适的做法 |
|---|---|---|
| 把 v4 当重置密码链接的唯一因子且长期有效 | 若链接可枚举或日志泄露,缺少额外密钥与短过期 | 高熵 token + 哈希存储 + 短 TTL + 单次使用 |
| 把 UUID 当 API Secret 放进查询串 | 进 Referer、代理日志、浏览器历史 | 放 Header,使用专用密钥,可轮换 |
| 用 UUID 替代登录会话签名 | 仅唯一不证明来源 | 签名 Cookie / JWT(并正确验签)等 |
| 认为「藏在 UUID 里的时间」可作权限 | v7/ULID 时间可被读出 | 授权用服务端策略,不靠 ID 编码 |
| 客户端自造 UUID 当支付单号且无校验 | 可伪造引用 | 服务端签发 + 状态机 |
需要机密随机串时,用 密码生成器 或服务端 CSPRNG 生成足够长度的 token,并只存哈希。UUID 生成器解决标识,不解决认证。
4. 输出格式选项
| 选项 | 效果 | 适用 |
|---|---|---|
| 标准小写 | 带连字符小写十六进制(ULID 则小写 Base32) | 多数代码与文档默认 |
| 标准大写 | 大写 | 强制大写的遗留系统 |
| 无连字符 | 去掉 - 的小写(对 UUID) |
某些文件名、紧凑存储;注意与标准文本互转 |
ULID 无连字符形态本身即连续字符;大小写按 lower/upper 处理。批量时每行一个 ID,可「全部复制」。
5. 逐步操作
- 打开 /tools/generator/uuid-generator。
- 在「标识符类型」选择 UUID v4、UUID v7(默认)或 ULID。
- 选择输出格式(小写 / 大写 / 无连字符)。
- 设置生成数量 1~1000;为 1 时大字号单条展示,大于 1 时进入批量文本框。
- 点 立即生成标识符;需要时 复制结果 / 全部复制。
- 清空结果 避免屏幕分享残留。
能力边界
- 支持: v4、v7、ULID、格式化、批量、本地生成。
- 不支持: 解析既有 UUID 的时间戳字段可视化、v1 MAC 地址模式、服务端发号保证全局单调(多机毫秒内顺序依赖实现细节)。
- ULID 实现以页面脚本为准;生产环境请与所用语言库的规范实现对齐并做抽样单测。
6. 主键与索引:为何大家转向 v7
随机 v4 作为聚簇主键时,新插入分散在索引各处,可能带来更多页分裂与缓存失效——在高写入表上可测到差异。v7/ULID 把时间放在排序键前面,插入更接近追加。
| 场景 | 更稳妥的选择 | 说明 |
|---|---|---|
| 公开资源 ID、希望不暴露量级 | v4 或随机 token | 有序 ID 可能泄露业务节奏 |
| 高写入订单表主键 | v7 或 ULID,或雪花等 | 配合唯一约束 |
| 仅关联用、非聚簇 | v4 往往足够 | 看存储与 ORM |
| 短链、展示给用户 | ULID 或有序且短的编码 | 注意可排序带来的信息 |
空间上 UUID 二进制 16 字节,文本更长;现代硬件下灵活性常优于自增在分库上的协调成本,但不是无脑替换一切整数主键。
7. 真实工作场景
场景 A:微服务消息去重
为每条出站消息生成 v4 或 v7 作 message_id,消费者幂等表唯一索引。这里要的是唯一与可追踪,不是保密。
场景 B:上传文件临时名
{uuid}.pdf 避免冲突;权限仍靠对象存储策略与签名 URL,不靠「猜不到文件名」当唯一安全措施(文件名可泄露)。
场景 C:从自增迁移到 UUID
双写或映射表阶段批量生成 v7,保持时间大致可排序,降低切换期运维焦虑。迁移脚本用批量 1000 内生成再导入。
场景 D:误把 UUID 当邀请码
邀请码需要防刷、频控与熵;改用专用生成与哈希存储。UUID 可作内部主键,对外邀请码另列。
场景 E:日志关联
前后端、网关用同一 request_id(v4 即可)串起一次调用。注意日志脱敏,ID 本身一般可留。
场景 F:教学对比有序性
连续生成 20 个 v7 与 20 个 v4,观察字典序是否大致随时间递增;用来解释索引行为,而不是证明「绝对单调全局时钟」。
9. 清单:生成之后
- 数据库唯一约束是否已加
- 对外暴露的 ID 是否可接受时间有序信息(v7/ULID)
- 是否错误地当作密码或 API Secret
- 文本格式(连字符、大小写)是否与校验正则一致
- 批量导入是否去重、是否与环境(测/产)隔离
- 客户端生成的 ID 服务端是否仍校验归属与状态
常见问题
UUID v4 真的永不重复吗?
在正确使用 CSPRNG 的前提下,碰撞概率可忽略,但工程上仍加唯一约束。重复一旦出现,优先查代码是否写死种子、是否用了非加密 Math.random 自制「假 UUID」。
为什么工具默认偏 v7?
许多现代库表主键希望时间有序;页面默认 v7 是产品选择。若你需要隐藏时间信息,请主动改选 v4。
ULID 和 UUID v7 怎么选?
都要有序时:要标准 UUID 形态、生态兼容 → v7;要更短 Base32、偏 API 路径 → ULID。团队只选一种主格式,避免混存。
无连字符还是 UUID 吗?
是同一 128 位的另一种文本写法。正则与数据库函数要注意是否期望带连字符;存二进制类型时可避免纠结。
可以本地生成当支付单号吗?
可以作候选 ID,但支付状态、金额、权限必须在服务端权威处理,并防重放。ID 唯一不等于支付完成。
浏览器生成安全吗?
本工具用 crypto.getRandomValues 填充随机段(实现以页面脚本为准)。公共屏幕上生成的 ID 若当秘密仍会肩窥泄露——秘密不要长期展示在投影上。
批量 1000 会卡死吗?
现代浏览器通常瞬间完成;更大批量应在服务端或专用脚本生成。
v1 UUID 呢?
本页不提供。v1 含时间与节点信息,隐私与网络拓扑顾虑更多;新系统优先 v4/v7。
ID 设计与数据治理
选 UUID 版本前先明确用途。数据库主键通常关心碰撞概率、索引写入顺序和跨系统生成能力;日志关联 ID 还要考虑是否需要按时间排序;公开链接则要考虑是否会暴露创建时间或业务规模。UUID v4 随机性强但无序,v7 更适合按时间写入和检索,实际选择应结合数据库索引、分片策略和隐私要求。无论使用哪种版本,都不要把 UUID 当作权限凭证,服务端仍需检查资源归属。
团队还应统一大小写、连字符、存储类型和 API 序列化格式。写入数据库时可以用原生 16 字节或规范化字符串,但不能让同一字段在不同服务中一会儿带连字符、一会儿不带。迁移旧系统时先统计重复、空值和大小写差异,再做批量转换;上线前用回放数据验证查询、分页和日志关联没有改变。生成器负责提供候选标识,生命周期、撤销和访问控制仍属于业务系统。
继续浏览
生成 5 个 v4 与 5 个 v7,观察排序差异;若下一步要做登录口令,请改用密码生成器而不是 UUID。