springboot3 uuid 唯一标识入门与实战
Uuid 项目
https://gitee.com/supervol/loong-springboot-study
(记得给个start,感谢)
Uuid 概述
在 Spring Boot 3 环境中,UUID(Universally Unique Identifier)是一种广泛使用的唯一标识符,用于分布式系统中标识资源。UUID 通过不同算法生成,形成了多个版本(V1 到 V7),各版本适用于不同场景。
UUID 是 128 位的二进制值,通常以 36 个字符的字符串表示(如f81d4fae-7dec-11d0-a765-00a0c91e6bf6),由 5 个部分组成,通过连字符分隔。其核心优势是全局唯一性,无需中央协调即可生成,适合分布式系统。uuid-creator是一个 Java 库,完全兼容 RFC 9562(替代 RFC 4122),实现了 V1 到 V7 的所有版本,解决了 JDK 自带UUID类的诸多问题(如无法生成 V1、V5,排序异常等)。
Uuid 详解
1. UUID V1
- 特点:基于当前时间戳(格林威治时间 1582 年 10 月 15 日起的 100 纳秒间隔)和节点标识符(通常是 MAC 地址)生成。
- 优势:可通过时间戳追溯生成时间,唯一性依赖时间和节点。
- 劣势:可能泄露 MAC 地址(存在隐私风险);时间戳在高位,字符串排序与生成时间不一致。
- 适用场景:需要按生成时间追溯的场景(如日志、事件序列)。
import com.github.f4b6a3.uuid.UuidCreator;
import java.util.UUID;// 生成V1 UUID(默认使用随机节点标识符)
UUID uuidV1 = UuidCreator.getTimeBased();// 生成V1 UUID(使用MAC地址作为节点标识符)
UUID uuidV1WithMac = UuidCreator.getTimeBasedWithMac();
2. UUID V2
- 特点:基于 V1 扩展,嵌入了本地域(如 POSIX UID/GID)和标识符,时间戳部分被截断以容纳域信息。
- 优势:结合了时间和本地系统标识(如用户 ID),适合安全场景。
- 劣势:使用场景有限,依赖本地系统域定义。
- 适用场景:分布式安全系统(如权限控制、用户关联)。
import com.github.f4b6a3.uuid.UuidCreator;
import com.github.f4b6a3.uuid.enums.UuidLocalDomain;// 生成V2 UUID(用户域,标识符1234)
UUID uuidV2 = UuidCreator.getDceSecurity(UuidLocalDomain.LOCAL_DOMAIN_PERSON, 1234);
3. UUID V3
- 特点:基于 “命名空间 + 名称” 的 MD5 哈希生成,相同命名空间和名称始终生成相同 UUID。
- 优势:确定性(相同输入生成相同结果),适合将名称映射为唯一标识。
- 劣势:MD5 哈希安全性较低(存在碰撞风险)。
- 适用场景:需要通过名称生成固定 UUID 的场景(如 URL、域名映射)。
import com.github.f4b6a3.uuid.UuidCreator;
import com.github.f4b6a3.uuid.enums.UuidNamespace;// 生成V3 UUID(URL命名空间,名称为GitHub地址)
UUID uuidV3 = UuidCreator.getNameBasedMd5(UuidNamespace.NAMESPACE_URL, "https://github.com/");
4. UUID V4
- 特点:基于随机数生成(122 位随机位 + 6 位版本 / 变体位),无时间或名称依赖。
- 优势:生成简单,无隐私泄露风险,性能较高。
- 劣势:不可追溯生成时间,大量生成时存在极低碰撞概率(理论上可忽略)。
- 适用场景:大多数通用场景(如主键、会话 ID、随机令牌)。
import com.github.f4b6a3.uuid.UuidCreator;// 生成标准V4 UUID(加密安全随机数)
UUID uuidV4 = UuidCreator.getRandomBased();// 生成快速V4 UUID(非加密安全,使用ThreadLocalRandom,适合非安全场景)
UUID uuidV4Fast = UuidCreator.getRandomBasedFast();
5. UUID V5
- 特点:基于 “命名空间 + 名称” 的 SHA-1 哈希生成,与 V3 类似但哈希算法更安全。
- 优势:确定性,SHA-1 安全性高于 MD5(碰撞风险极低)。
- 劣势:哈希计算比 V3 稍重。
- 适用场景:需通过名称生成固定 UUID 且对安全性要求较高的场景(如分布式系统中的资源映射)。
import com.github.f4b6a3.uuid.UuidCreator;
import com.github.f4b6a3.uuid.enums.UuidNamespace;// 生成V5 UUID(URL命名空间,名称为Loong地址)
UUID uuidV5 = UuidCreator.getNameBasedSha1(UuidNamespace.NAMESPACE_URL, "https://loong.com/");
6. UUID V6
- 特点:对 V1 的时间戳重新排序(高位放时间戳),解决 V1 字符串排序与生成时间不一致的问题,兼容 V1 的时间戳格式(格林威治时间)。
- 优势:时间戳在高位,字符串排序与生成时间一致,适合数据库索引(提升查询性能)。
- 劣势:仍依赖节点标识符(可能泄露 MAC)。
- 适用场景:需要按生成时间排序的场景(如数据库主键、时序数据)。
import com.github.f4b6a3.uuid.UuidCreator;// 生成V6 UUID
UUID uuidV6 = UuidCreator.getTimeOrdered();
7. UUID V7
- 特点:基于 Unix 时间戳(毫秒级,从 1970 年 1 月 1 日起)+ 随机数生成,时间戳在高位,天然支持排序。
- 优势:
- 时间戳基于 Unix epoch(更符合现代系统);
- 字符串排序与生成时间一致,适合数据库索引;
- 无节点标识符依赖,隐私性更好;
- 适合高并发分布式系统(通过时间戳 + 随机数避免碰撞)。
- 适用场景:分布式数据库主键、高并发系统的唯一标识(如微服务接口 ID)。
import com.github.f4b6a3.uuid.UuidCreator;// 生成V7 UUID
UUID uuidV7 = UuidCreator.getTimeOrderedEpoch();
Uuid 示例
请参考项目地址中 springboot-db/springboot-id 模块代码。
Uuid 实现
1. 引入依赖
uuid-creator最新版本为 6.1.1,在pom.xml中添加依赖:
<dependency><groupId>com.github.f4b6a3</groupId><artifactId>uuid-creator</artifactId><version>6.1.1</version>
</dependency>
2. 项目中使用
在 Service 或 Component 中直接调用UuidCreator的静态方法生成 UUID,例如在实体类中作为主键:
import com.github.f4b6a3.uuid.UuidCreator;
import lombok.Data;@Data
public class User {private String id;public User() {// 使用V7作为主键(适合分布式系统)this.id = UuidCreator.getTimeOrderedEpoch().toString();}}
3. 工具类扩展
可封装工具类简化调用:
import com.github.f4b6a3.uuid.UuidCreator;@Component
public class UuidGenerator {// 生成V7 UUID(默认推荐)public String generateV7() {return UuidCreator.getTimeOrderedEpoch().toString();}// 生成V4 UUID(快速非安全版)public String generateV4Fast() {return UuidCreator.getRandomBasedFast().toString();}// 其他版本生成方法...
}
Uuid 高级
- 替代 JDK 的
UUID类:提供GUID作为独立实现,生成方法更简洁(如GUID.v7()),可转换为 JDK 的UUID(GUID.v7().toUUID())。 - 工具类支持:
UuidUtil:提取 UUID 的时间戳、节点标识符等信息(如UuidUtil.getInstant(uuid)获取生成时间)。UuidValidator:验证 UUID 字符串合法性(UuidValidator.isValid(uuidStr))。UuidComparator:解决 JDKUUID.compareTo()的排序问题,支持按生成时间排序。
Uuid 对比
1. 同类对比
Java 自带的 java.util.UUID 是 JDK 内置的 UUID 生成工具,而 uuid-creator 是第三方库(基于 RFC 9562 标准),两者在功能、兼容性、适用场景上有显著差异,具体对比如下:
| 对比维度 | Java 自带 java.util.UUID | uuid-creator(v6.1.1) |
|---|---|---|
| 支持的版本 | 仅支持 V3(名称基 MD5)、V4(随机基);名义上支持 V1(时间基),但实现存在缺陷(如节点标识符随机化,时间戳排序异常);不支持 V2、V5、V6、V7。 | 完全支持 V1 到 V7 所有版本,且严格遵循 RFC 9562 标准(替代旧版 RFC 4122)。 |
| 生成逻辑与缺陷 | - V1:时间戳高位存储导致字符串排序与生成时间不一致;节点标识符默认随机化(失去时间追溯的准确性)。- 无 V5 实现(SHA-1 哈希),无法满足高安全性的名称映射需求。- 无有序 UUID(V6、V7),不适合数据库索引场景。 | - V1:修复节点标识符逻辑(可指定 MAC 地址或随机节点)。- 新增 V5(SHA-1 哈希),弥补 V3 安全性不足。- 实现 V6(V1 时间戳重排序)和 V7(Unix 时间戳 + 随机数),解决有序性问题。 |
| 功能工具链 | 仅提供基础生成(randomUUID()、nameUUIDFromBytes())和解析(fromString()),无额外工具。 | 提供丰富工具类:- UuidUtil:提取 UUID 时间戳(getInstant(uuid))、节点信息等;- UuidValidator:验证 UUID 合法性;- UuidComparator:按生成时间排序(解决 JDK 排序异常)。 |
| 性能与安全性 | - V4 生成依赖 SecureRandom,性能较低(适合安全场景,但非安全场景冗余)。- 无 “快速随机” 选项。 | - V4 提供两种模式:getRandomBased()(加密安全,SecureRandom)和 getRandomBasedFast()(非加密安全,ThreadLocalRandom,性能提升 10x+)。- 所有版本生成逻辑经过优化,减少不必要的计算开销。 |
| 分布式与兼容性 | 无针对分布式场景的优化(如高并发下的碰撞规避)。 | 针对分布式场景设计:- V7 通过 “毫秒时间戳 + 随机数” 避免高并发碰撞;- 所有版本生成逻辑无中央协调依赖,适合分布式系统。 |
| 适用场景 | 简单场景(如临时唯一标识),不适合有序性、高安全性、分布式需求。 | 全场景覆盖:从简单随机 ID(V4)到有序分布式主键(V7),从安全权限标识(V2)到名称映射(V3/V5)。 |
总结:Java 自带 UUID 仅能满足最基础的需求,而 uuid-creator 弥补了其版本支持不足、功能简陋、性能优化缺失等问题,是分布式系统中 UUID 生成的更优选择。
2. 有序对比
有序 ID 是指生成顺序与字符串 / 数值排序一致的标识符,适合数据库索引(提升查询性能)、时序数据排序等场景。常见的有序 ID 包括雪花算法(Snowflake)、MongoDB ObjectId、UUID V6、递增整数等。uuid-creator 的 V7 UUID 与这些方案的对比如下:
| 对比维度 | UUID V7(uuid-creator) | 雪花算法(Snowflake) | MongoDB ObjectId | UUID V6 | 递增整数(如自增 ID) |
|---|---|---|---|---|---|
| 结构与长度 | 128 位(36 字符字符串):48 位 Unix 毫秒时间戳 + 12 位随机序列号 + 62 位随机数(含版本位)。 | 64 位(数值):41 位毫秒时间戳 + 10 位机器 ID + 12 位序列号。 | 96 位(24 字符十六进制):32 位秒级时间戳 + 24 位机器 ID + 16 位进程 ID + 24 位计数器。 | 128 位(36 字符):V1 时间戳重排序(高位放时间戳)。 | 32/64 位(数值):单调递增。 |
| 有序性 | 严格按生成时间排序(时间戳在高位,字符串排序 = 生成顺序)。 | 按时间戳 + 序列号排序,有序性强。 | 按秒级时间戳排序(精度低于毫秒),同一秒内依赖计数器有序。 | 按 V1 时间戳排序(精度 100 纳秒,但基于格林威治时间 1582 年,与现代系统时间不兼容)。 | 绝对有序(依赖数据库自增)。 |
| 分布式支持 | 无需中央协调:时间戳 + 随机数避免碰撞,支持跨服务 / 跨机房生成。 | 依赖机器 ID 分配(需提前协调,否则可能冲突);存在时钟回拨风险(需额外处理)。 | 依赖机器 ID + 进程 ID(需确保唯一,否则冲突);计数器在单进程内有效,跨进程可能重复。 | 依赖节点标识符(MAC 地址或随机,随机节点可能冲突)。 | 需中央协调(如数据库自增锁),分布式场景易冲突。 |
| 隐私与安全性 | 无机器 / 进程信息,隐私性好;随机部分降低可预测性。 | 暴露机器 ID,存在隐私泄露风险;结构固定,易被预测。 | 暴露机器 ID 和进程 ID,隐私性差。 | 可能暴露 MAC 地址(隐私风险)。 | 完全可预测(安全性差)。 |
| 兼容性 | 完全兼容 UUID 标准(RFC 9562),支持所有系统 / 数据库(如 MySQL、PostgreSQL 原生支持 UUID 类型)。 | 非标准格式,需自定义存储(如 BIGINT),跨系统兼容性差。 | MongoDB 专用格式,其他系统需额外解析。 | 兼容 UUID 标准,但时间戳基于旧 epoch(1582 年),现代系统需转换。 | 兼容性好,但分布式场景需额外处理冲突。 |
| 适用场景 | 分布式数据库主键、高并发系统唯一标识(如微服务接口 ID)、需排序且隐私性要求高的场景。 | 单一集群内的有序 ID(如电商订单号),不适合跨集群 / 跨组织场景。 | MongoDB 生态内的文档标识,不适合其他数据库。 | 需要兼容 V1 且有序的场景(较少见)。 | 单体应用、非分布式场景(如后台管理系统)。 |
V7 UUID 的核心优势:
- 平衡有序性与分布式:基于 Unix 毫秒时间戳保证有序,随机部分避免分布式冲突,无需中央协调。
- 标准化与兼容性:遵循 UUID 标准,适配所有支持 UUID 的系统,无需自定义存储格式。
- 隐私与安全性:无机器信息泄露,随机部分降低可预测性,适合敏感场景(如用户 ID)。
- 时间精度与现代性:基于 Unix epoch(1970 年),与现代系统时间一致,无需转换。
总结:在分布式、高并发、需有序性的场景中,V7 UUID 是比雪花算法、ObjectId 等更优的选择,尤其适合跨系统、跨组织的唯一标识需求。
Uuid 总结
| 版本 | 核心算法 | 优势 | 适用场景 | uuid-creator方法 |
|---|---|---|---|---|
| V1 | 时间戳 + MAC 地址 | 可追溯时间 | 日志、事件序列 | getTimeBased() |
| V2 | 时间戳 + 本地域 + 标识符 | 结合本地安全标识 | 权限控制 | getDceSecurity() |
| V3 | 名称 + 命名空间 + MD5 | 确定性映射 | URL / 域名映射 | getNameBasedMd5() |
| V4 | 随机数 | 简单、无隐私泄露 | 通用场景(主键、会话 ID) | getRandomBased()/getRandomBasedFast() |
| V5 | 名称 + 命名空间 + SHA-1 | 确定性 + 高安全性 | 高安全的名称映射 | getNameBasedSha1() |
| V6 | 重排序时间戳(V1 改进) | 时间有序,适合索引 | 时序数据、数据库主键 | getTimeOrdered() |
| V7 | Unix 时间戳 + 随机数 | 现代时间戳、排序友好、分布式友好 | 分布式数据库、高并发系统 | getTimeBasedEpoch() |
在 Spring Boot 3 中,推荐优先使用 V4(简单场景)或 V7(分布式 / 排序场景),通过uuid-creator可便捷集成所有版本,解决 JDK 原生 UUID 的缺陷。
