UUID(Universally Unique Identifier,通用唯一识别码)是软件开发中常用的一种唯一标识生成方式,广泛应用于数据库主键、分布式系统ID、文件名称、订单编号、接口请求标识等场景。Java提供了内置的UUID工具类,可以方便地生成符合标准格式的唯一字符串。
Java中的UUID生成方式主要依赖java.util.UUID类,该类基于RFC 4122标准实现,能够生成128位的唯一标识。UUID通常表现为32个十六进制字符,由4个短横线分隔,例如:
550e8400-e29b-41d4-a716-446655440000
一个标准UUID由五个部分组成:
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
其中M表示UUID版本号,N表示变体信息。Java默认生成的是UUID版本4,也就是基于随机数生成的UUID。
Java使用UUID生成唯一标识
Java生成UUID最常用的方法是调用UUID.randomUUID()。
示例代码:
Javaimport java.util.UUID; public class UUIDDemo { public static void main(String[] args) { UUID uuid = UUID.randomUUID(); System.out.println(uuid); } }
运行结果:
9f8c6d52-5c8e-4e89-9d88-8c8c3e3a4f12
每次执行程序都会生成一个新的UUID。
UUID.randomUUID()返回的是UUID对象,如果需要字符串格式,可以调用toString()方法:
JavaString id = UUID.randomUUID().toString(); System.out.println(id);
输出:
d3b07384-d9a6-4d5f-8c72-4e4b7f5f8d21
这种方式是Java项目中最常见的UUID生成方式。
UUID生成字符串并去除横线
很多业务场景中,例如数据库字段、文件名或者接口参数,不希望UUID中包含短横线,可以通过字符串替换实现。
示例:
JavaString uuid = UUID.randomUUID() .toString() .replace("-", ""); System.out.println(uuid);
输出:
c6a7d4e91e564cbf8a3d8d5f6e7a9b10
去除短横线后的UUID长度为32位,更适合作为数据库字段存储。
例如MySQL中常见设计:
SQLCREATE TABLE user ( id VARCHAR(32) PRIMARY KEY, username VARCHAR(50) );
Java插入数据时:
JavaString id = UUID.randomUUID() .toString() .replace("-", "");
这样可以避免数据库自增ID暴露业务增长规律。
Java UUID的常用方法介绍
java.util.UUID除了生成UUID外,还提供了一些常用操作方法。
获取UUID字符串
JavaUUID uuid = UUID.randomUUID(); String value = uuid.toString();
toString()会返回标准UUID格式。
获取UUID高64位和低64位
UUID实际上由两个64位数字组成:
JavaUUID uuid = UUID.randomUUID(); long most = uuid.getMostSignificantBits(); long least = uuid.getLeastSignificantBits(); System.out.println(most); System.out.println(least);
这两个方法常用于底层存储优化。
例如数据库中可以使用两个BIGINT字段保存UUID,比VARCHAR存储更加节省空间。
根据字符串创建UUID
如果已经存在符合UUID格式的字符串,可以通过fromString()转换:
JavaString str = "550e8400-e29b-41d4-a716-446655440000"; UUID uuid = UUID.fromString(str); System.out.println(uuid);
如果字符串格式错误,会抛出:
IllegalArgumentException
因此实际开发中通常需要提前校验输入。
UUID版本类型介绍
UUID标准定义了多个版本,不同版本生成方式不同。
UUID Version 1:基于时间生成
UUID v1主要根据:
-
时间戳
-
机器MAC地址
-
时钟序列
生成唯一ID。
优点:
-
时间有序
-
重复概率极低
缺点:
-
可能泄露机器信息
-
Java标准UUID类没有直接提供v1生成方法
UUID Version 3:基于名称和MD5
UUID v3根据命名空间和名称,通过MD5算法生成。
特点:
-
同样输入生成相同UUID
-
适合固定映射场景
例如:
JavaUUID uuid = UUID.nameUUIDFromBytes( "example".getBytes() ); System.out.println(uuid);
Java中的nameUUIDFromBytes()默认生成UUID v3。
UUID Version 4:随机生成
Java中的:
JavaUUID.randomUUID()
生成的就是UUID v4。
特点:
-
基于随机数
-
不依赖机器信息
-
使用简单
目前互联网应用中最常见。
UUID Version 5:基于SHA算法
UUID v5与v3类似,但使用SHA-1算法替代MD5。
Java标准库没有直接支持,需要使用第三方库实现。
UUID在实际项目中的应用场景
1. 数据库主键
UUID可以作为数据库唯一ID。
例如:
Java@Entity public class User { private String id = UUID.randomUUID() .toString(); }
相比自增ID,UUID具有:
-
分布式生成能力
-
不依赖数据库
-
不容易被猜测
适合微服务架构。
2. 分布式系统ID生成
传统数据库自增ID在分布式环境中容易出现冲突。
例如:
订单服务:
订单ID:550e8400-e29b-41d4-a716-446655440000
不同服务器可以独立生成UUID,无需统一编号服务。
3. 文件唯一命名
上传文件时,为避免同名覆盖:
JavaString filename = UUID.randomUUID() + ".jpg";
生成:
a12bc456-789d-456e-b123-image.jpg
可以有效降低文件冲突概率。
4. 请求链路追踪
微服务调用过程中,可以生成UUID作为traceId:
JavaString traceId = UUID.randomUUID() .toString();
然后写入日志:
traceId=9f8c6d52-5c8e-4e89
方便排查跨服务问题。
UUID和雪花算法的区别
实际开发中,UUID经常会和雪花算法(Snowflake)进行比较。
| 对比项 | UUID | 雪花算法 |
|---|---|---|
| 长度 | 128位 | 64位 |
| 是否有序 | 否 | 是 |
| 是否依赖机器 | 否 | 是 |
| 数据库索引性能 | 较低 | 较高 |
| 分布式支持 | 支持 | 支持 |
| 可读性 | 较差 | 较好 |
UUID优势在于简单可靠,而雪花算法优势在于趋势递增和性能优化。
如果数据库使用UUID作为主键,随机写入可能导致B+Tree索引频繁分裂,影响性能。因此高并发业务通常会考虑:
-
使用有序UUID
-
使用雪花算法
-
使用数据库自增ID
Java生成UUID时的注意事项
1. 不要认为UUID绝对不会重复
UUID设计目标是极低概率重复,并不是数学意义上的绝对唯一。
UUID v4理论重复概率极低,但关键业务仍可以增加数据库唯一约束。
2. 注意存储格式
UUID标准格式:
36个字符
去掉横线:
32个字符
数据库设计时应根据实际需求选择:
SQLVARCHAR(36)
或者:
SQLCHAR(32)
3. 避免频繁创建无意义UUID
UUID生成虽然开销较小,但大量循环生成时仍会产生额外计算成本。
例如:
Javafor(int i=0;i<1000000;i++){ UUID.randomUUID(); }
如果只是临时计算,没有必要生成UUID。
4. 不要直接暴露敏感业务信息
UUID虽然不像自增ID那样容易推测数量,但它本身不是加密机制。
涉及安全认证时,应使用:
-
Token
-
加密签名
-
随机密钥
而不是单纯依赖UUID。
总结
Java中的UUID生成主要通过java.util.UUID实现,其中最常用的方法是UUID.randomUUID()。它能够快速生成符合标准的唯一标识,适用于用户ID、订单编号、文件名称、分布式系统标识等多种场景。
在普通业务开发中,UUID v4已经能够满足绝大多数唯一ID需求。但在高并发、大规模数据库场景下,需要结合索引性能、数据排序需求以及系统架构选择合适的ID方案。合理使用UUID,可以提升系统的扩展能力和数据管理效率。