🪪 UUID/GUID 完全指南:什么是 UUID、版本区别与生成方法
2026-06-24 · 约 8 分钟
做开发的朋友一定见过这样的东西:550e8400-e29b-41d4-a716-446655440000。这就是 UUID(Universally Unique Identifier,通用唯一标识符)。很多地方也叫它 GUID(Globally Unique Identifier,全局唯一标识符),两者是同一个东西的两种叫法。
这篇文章会从头讲清楚:UUID 是什么、不同版本有什么区别、你在不同语言里怎么生成它,以及什么时候该用什么时候不该用。
什么是 UUID?
UUID 是一个 128 位的数字,通常用 32 个十六进制字符表示,中间加四个短横线分成五段:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
它的核心价值就四个字:全球唯一。理论上说,只要生成策略正确,全世界范围内产生的 UUID 都不会重复——不需要中心服务器分配,不需要联网,你本地就能生成一个保证不跟别人撞车的 ID。
标准定义在 RFC 4122 里,目前有 5 个正式版本,还有几个实验性版本。
UUID 各版本对比
| 版本 | 名称 | 生成方式 | 唯一性 | 适用场景 |
|---|---|---|---|---|
| v1 | 基于时间 | 当前时间戳 + MAC 地址 | 极高 | 分布式系统,但不推荐(暴露 MAC 地址) |
| v3 | 基于命名空间/MD5 | MD5(namespace + name) | 确定性 | 同一输入生成同一 UUID |
| v4 | 随机 UUID | 随机数 | 极高 | 最常用,几乎所有场景 |
| v5 | 基于命名空间/SHA-1 | SHA-1(namespace + name) | 确定性 | 比 v3 更安全的确定性 UUID |
| v7 | 基于时间排序 | 时间戳 + 随机数 | 极高 | MySQL 主键、数据库排序优化(新标准) |
UUID v4 — 日常开发首选
UUID v4 是目前最常用的版本。它除了版本位和变体位是固定的之外,其余 122 位全部用随机数填充。理论上重复概率极低——要产生 50% 的碰撞概率,需要生成约 2.71 × 10¹⁸ 个 UUID。
简单说:你可以放心用,不会撞车。
UUID v7 — 数据库友好型
UUID v7 是 2024 年新标准(RFC 9562)引入的。它的前 48 位是毫秒级时间戳,后面是随机数。好处是:按时间有序。
如果你用过 UUID v4 做 MySQL/PostgreSQL 的主键,你一定遇到过这个问题:随机 UUID 会导致 B+ 树索引频繁分裂,写入性能暴跌。UUID v7 按时间递增,完美解决了这个痛点。很多现代数据库(MySQL 8.0+、PostgreSQL、CockroachDB)都推荐用它替代自增 ID。
各语言生成 UUID
JavaScript / Node.js
// 浏览器原生
const id = crypto.randomUUID(); // "550e8400-e29b-41d4-a716-446655440000"
// Node.js
import { randomUUID } from 'node:crypto';
randomUUID(); // v4
// UUID v7 (Node 22+)
import { randomUUID, uuidv7 } from 'node:crypto';
// v7 需额外支持或使用 uuid 库
Python
import uuid
# v4 随机 UUID
u = uuid.uuid4()
print(str(u)) # "550e8400-e29b-41d4-a716-446655440000"
# v7 时间排序 UUID(需 uuid 库 >= 9.0)
!pip install uuid7
import uuid7
print(str(uuid7.uuid7()))
Java
import java.util.UUID;
// v4 随机 UUID
UUID uuid = UUID.randomUUID();
System.out.println(uuid.toString());
// v7 需要第三方库或自实现
// 推荐: com.fasterxml.uuid 或 com.github.f4b6a3:tsid-creator
Go
import "github.com/google/uuid"
// v4 随机 UUID
id := uuid.New().String()
// v7 时间排序 UUID
id := uuid.Must(uuid.NewV7()).String()
PHP
// v4 随机 UUID
$uuid = Ramsey\Uuid\Uuid::uuid4();
echo $uuid->toString(); // "550e8400-e29b-41d4-a716-446655440000"
// v7
$uuid = Ramsey\Uuid\Uuid::uuid7();
echo $uuid->toString();
UUID 的应用场景
- 数据库主键: 推荐用 v7 替代自增 ID,避免合并冲突,也方便分库分表
- 用户 ID / 订单号: 不暴露注册人数和订单量
- API 请求追踪: 每个请求带 x-request-id,方便排查日志
- 文件/资源标识: 上传文件重命名为 UUID,避免重名和路径遍历漏洞
- 分布式系统: 多节点无需协调即可生成唯一 ID
什么时候不要用 UUID
- 短 ID 需要: 短信验证码、优惠券码——用 NanoID 或自定义短码,长度可控
- URL 友好需要: 公开 URL 参数里一长串 UUID 既不美观也不方便——考虑用 HashID 或 Snowflake
- 超大表排序: 即使 v7 也比自增 BIGINT 占用更多空间(128 vs 64 位),十亿级表要考虑存储成本
- 用户可见 ID: 别让用户看到 "您的工单号:550e8400-e29b-41d4-a716-446655440000",用户体验很差
常见问题
Q: UUID 和 GUID 有区别吗?
没有本质区别。GUID 是微软的称呼,遵循的是同一标准(RFC 4122),格式一模一样。两者可以互换使用。
Q: UUID v4 真的不会重复吗?
理论上会,但概率极低。一年内产生碰撞的概率大约是一万亿分之一。你被雷劈中的概率都比它高几百万倍。放心用。
Q: 应该用 v4 还是 v7?
如果做数据库主键,推荐 v7——有序插入避免索引碎片。做普通标识符(请求 ID、资源 ID),v4 足够好,生态也更成熟。不确定的话选 v4 不会错。