前端JavaScript生成UUID
import { v4 as uuidv4 } from "uuid";
// 请求唯一ID
const requestId = ref("");
// 生成请求唯一ID
if (typeof crypto !== "undefined" && crypto.randomUUID) {
// 使用 Web 标准(Web Crypto API)
requestId.value = crypto.randomUUID();
} else {
// 使用第三方库 uuid
requestId.value = uuidv4();
}
深入理解 crypto 和 randomUUID()
-
关于 crypto 对象:
crypto是一个全局的内置对象,它提供了密码学相关的基础功能。这个对象不是第三方库,而是 Web 标准(Web Crypto API)的一部分,由浏览器或 Node.js 运行时原生提供,因此非常可靠且性能优异。 -
关于 randomUUID() 方法:
这个方法是crypto对象的一个属性,专门用于生成符合 RFC 4122 版本 4 标准的通用唯一标识符(UUID)。它的工作原理可以简单理解为:正因为其底层是加密级的强随机源,且组合空间巨大(2^122 种可能),使得它在工程上可以被认为是“全球唯一”的,碰撞概率极低,远超
Math.random()。-
它使用密码学安全的随机数生成器(CSPRNG) 来生成一个长度为 122 位的真正随机数。
-
按照 UUID v4 的标准格式(8-4-4-4-12 的十六进制数字,由连字符分隔)将这个随机数组装成字符串。
-
版本号“4”被固定在特定位置,以标识其生成方式。
-
兼容性与使用建议
crypto.randomUUID() 的兼容性在今天已经非常好:
-
现代浏览器:Chrome 92+、Edge 92+、Firefox 90+、Safari 15.4+ 均已原生支持。
-
Node.js:从 v14.17.0 开始也内置了此方法。
-
根据主流统计,全球浏览器支持率已超过92%。
数据库生成UUID
SQL Server 2008 R2 生成UUID
-- 并发优化:使用会话结果表名(UUID)来避免并发冲突,由原来固定的##Result改为动态唯一的##Result_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
declare @SessionResultTable varchar(50) = '##Result_' + replace(cast(newid() as varchar(36)), '-', '')
后端Spring Boot生成UUID
import java.util.UUID;
// 生成随机UUID
UUID uuid = UUID.randomUUID();
String uuidString = uuid.toString(); // 转换为字符串格式
// 示例
UUID id = UUID.randomUUID();
System.out.println(id.toString()); // 输出:123e4567-e89b-42d3-a456-a26614174000
Java原生UUID.randomUUID()生成的是UUID v4
详细说明
1. Java原生UUID类只能生成v4
Java标准库中的UUID.randomUUID()方法只能生成版本4的UUID(随机UUID):
java
import java.util.UUID;
public class JavaUUIDVersion {
public static void main(String[] args) {
UUID uuid = UUID.randomUUID();
System.out.println("UUID: " + uuid);
System.out.println("版本号: " + uuid.version()); // 输出: 4
System.out.println("变体: " + uuid.variant()); // 输出: 2
// 验证格式
String hex = uuid.toString();
System.out.println("第15个字符(版本位): " + hex.charAt(14)); // 输出: '4'
// 所有Java生成的UUID都是v4
for (int i = 0; i < 5; i++) {
UUID testUuid = UUID.randomUUID();
System.out.println(testUuid + " -> 版本: " + testUuid.version());
}
}
}
2. Java UUID类的局限性
Java标准库只提供:
-
v4生成:
UUID.randomUUID() -
名称UUID v3/v5生成:
UUID.nameUUIDFromBytes(byte[] name) -
解析:
UUID.fromString(String name) -
比较操作:
compareTo(),equals(),hashCode()
没有内置的v1、v2、v6、v7、v8生成支持
3. 验证代码
java
import java.util.UUID;
public class UUIDVersionChecker {
public static void main(String[] args) {
System.out.println("=== Java原生UUID版本验证 ===");
// 生成10个UUID并检查版本
for (int i = 0; i < 10; i++) {
UUID uuid = UUID.randomUUID();
String hex = uuid.toString();
System.out.printf("%nUUID %d: %s%n", i + 1, hex);
System.out.printf(" 版本位(第15字符): '%c' → ", hex.charAt(14));
char versionChar = hex.charAt(14);
switch (versionChar) {
case '1':
System.out.println("v1 (基于时间)");
break;
case '3':
System.out.println("v3 (基于名称的MD5)");
break;
case '4':
System.out.println("v4 (随机) ← Java默认");
break;
case '5':
System.out.println("v5 (基于名称的SHA-1)");
break;
default:
System.out.println("未知版本");
}
// 使用version()方法验证
System.out.printf(" uuid.version() = %d%n", uuid.version());
}
System.out.println("\n=== 结论 ===");
System.out.println("Java的UUID.randomUUID() 总是生成 v4 UUID");
System.out.println("UUID.version() 方法总是返回 4");
}
}
4. 如何查看UUID版本
UUID的版本信息存储在第13-16位(字符串表示的第15个字符):
text
UUID格式:xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
↑
M = 版本号(4 bits)
N = 变体号(2 bits)
十六进制表示:
-
M = 1→ v1(基于时间) -
M = 3→ v3(基于名称-MD5) -
M = 4→ v4(随机)← Java默认 -
M = 5→ v5(基于名称-SHA-1)
5. 如果需要其他版本UUID
选项1:使用第三方库(推荐)
xml
<!-- Maven依赖 -->
<dependencies>
<!-- 生成v1, v6, v7等 -->
<dependency>
<groupId>com.fasterxml.uuid</groupId>
<artifactId>java-uuid-generator</artifactId>
<version>4.3.0</version>
</dependency>
<!-- 或使用uuid-creator(支持更多版本) -->
<dependency>
<groupId>com.github.f4b6a3</groupId>
<artifactId>uuid-creator</artifactId>
<version>6.0.0</version>
</dependency>
</dependencies>
Java原生UUID正确的模式
Java原生UUID.randomUUID()生成的UUID必须符合以下正则表达式:
java
String v4Pattern = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$";
关键特征:
-
第15个字符必须是 '4'(版本号)
-
第20个字符必须是 '8', '9', 'a', 或 'b'(变体号)
-
其他字符是随机的十六进制数字
UUID v1 和 v4 的生成方式详解
UUID 版本对比
| 版本 | 名称 | 特点 | 排序性 | 安全性 |
|---|---|---|---|---|
| v1 | 基于时间戳 | 基于MAC地址和时间戳 | 按时间排序 | 较低(可能泄露MAC地址) |
| v4 | 随机生成 | 完全随机 | 无序 | 高 |
| v7 | 基于时间戳(新版) | Unix时间戳+随机数 | 按时间排序 | 高 |
1. UUID v1(基于时间戳)
生成原理
v1 UUID 基于以下要素生成:
-
时间戳:从1582-10-15到现在的100纳秒间隔数(60位)
-
时钟序列:防止时钟回拨(14位)
-
节点标识:通常是MAC地址(48位)
Java 生成示例
java
import com.fasterxml.uuid.Generators;
import java.util.UUID;
public class UUIDv1Generator {
public static void main(String[] args) {
// 使用java-uuid-generator库生成v1
// 需要添加依赖:com.fasterxml.uuid:java-uuid-generator
// 方法1:使用第三方库(推荐)
UUID uuidV1 = Generators.timeBasedGenerator().generate();
System.out.println("UUID v1: " + uuidV1);
System.out.println("版本: " + uuidV1.version()); // 输出 1
System.out.println("变体: " + uuidV1.variant()); // 输出 2
// 方法2:手动创建v1风格的UUID(不推荐,仅演示原理)
createV1StyleUUID();
}
private static void createV1StyleUUID() {
// 注意:这不是真正的v1 UUID,只是格式演示
long mostSigBits = 0x00000123_456789ABL;
long leastSigBits = 0x8000C001_23456789L;
UUID customV1 = new UUID(mostSigBits, leastSigBits);
System.out.println("自定义v1风格: " + customV1);
}
}
Maven依赖
xml
<dependency>
<groupId>com.fasterxml.uuid</groupId>
<artifactId>java-uuid-generator</artifactId>
<version>4.2.0</version>
</dependency>
v1 格式解析
text
示例:123e4567-e89b-11d3-a456-426614174000
└─ 版本位(1)表示v1
2. UUID v4(随机生成)
生成原理
v4 UUID 完全随机生成,其中:
-
第13个字符固定为 '4'(版本标识)
-
第17个字符为 '8'、'9'、'a' 或 'b'(变体标识)
-
其余122位完全随机
Java 生成示例
java
import java.util.UUID;
public class UUIDv4Generator {
public static void main(String[] args) {
// 方法1:标准方式(最常用)
UUID uuidV4 = UUID.randomUUID();
System.out.println("UUID v4: " + uuidV4);
System.out.println("版本: " + uuidV4.version()); // 输出 4
System.out.println("变体: " + uuidV4.variant()); // 输出 2
// 方法2:验证v4特性
validateV4UUID(uuidV4);
// 方法3:批量生成
System.out.println("\n批量生成v4 UUID:");
for (int i = 0; i < 3; i++) {
System.out.println(UUID.randomUUID());
}
}
private static void validateV4UUID(UUID uuid) {
String hex = uuid.toString();
char versionChar = hex.charAt(14);
char variantChar = hex.charAt(19);
System.out.println("第15位(版本位): " + versionChar + " (应为4)");
System.out.println("第20位(变体位): " + variantChar + " (应为8-9或a-b)");
if (versionChar == '4') {
System.out.println("✓ 这是有效的v4 UUID");
} else {
System.out.println("✗ 这不是v4 UUID");
}
}
}
v4 格式解析
text
示例:123e4567-e89b-42d3-a456-426614174000
└─ 版本位(4)表示v4
3. 新版 UUID v7(推荐用于时序排序)
UUID v7 是较新的版本,结合了时间排序性和安全性:
java
import com.github.f4b6a3.uuid.UuidCreator;
public class UUIDv7Generator {
public static void main(String[] args) {
// 需要依赖:com.github.f4b6a3.uuid-creator
// 生成v7 UUID
UUID uuidV7 = UuidCreator.getTimeOrdered();
System.out.println("UUID v7: " + uuidV7);
// v7基于Unix时间戳,具有更好的排序性
System.out.println("具有时间排序性的现代UUID");
}
}
4. Spring Boot 中按需选择生成策略
配置类示例
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.uuid.Generators;
import com.fasterxml.uuid.impl.TimeBasedGenerator;
import java.util.UUID;
@Configuration
public class UUIDConfig {
@Bean
public TimeBasedGenerator uuidV1Generator() {
return Generators.timeBasedGenerator();
}
@Bean(name = "uuidV4Generator")
public java.util.function.Supplier<UUID> uuidV4Generator() {
return UUID::randomUUID;
}
}
服务类中使用
java
import com.fasterxml.uuid.impl.TimeBasedGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.UUID;
@Service
public class OrderService {
@Autowired
private TimeBasedGenerator uuidV1Generator;
@Autowired
@Qualifier("uuidV4Generator")
private java.util.function.Supplier<UUID> uuidV4Generator;
public Order createOrder(OrderDTO dto, boolean needsTimeSorting) {
Order order = new Order();
if (needsTimeSorting) {
// 需要时间排序时使用v1
order.setId(uuidV1Generator.generate());
System.out.println("使用v1 UUID,可按时间排序");
} else {
// 否则使用v4(更安全)
order.setId(uuidV4Generator.get());
System.out.println("使用v4 UUID,更安全随机");
}
order.setItems(dto.getItems());
return orderRepository.save(order);
}
}
5. 性能与安全性对比
测试性能
java
import java.util.UUID;
public class UUIDPerformanceTest {
public static void main(String[] args) {
int iterations = 100000;
// 测试v4性能
long start = System.nanoTime();
for (int i = 0; i < iterations; i++) {
UUID.randomUUID();
}
long v4Time = System.nanoTime() - start;
System.out.println("生成 " + iterations + " 个v4 UUID 耗时: " +
(v4Time / 1000000) + "ms");
System.out.println("平均每个: " + (v4Time / iterations) + "ns");
}
}
6. 实际应用建议
场景1:需要时间排序(如日志、时序数据)
java
// 使用v1或v7
public class TimeSeriesData {
@Id
@GeneratedValue(generator = "uuid-v1")
@GenericGenerator(
name = "uuid-v1",
strategy = "org.hibernate.id.UUIDGenerator",
parameters = {
@Parameter(
name = "uuid_gen_strategy_class",
value = "com.fasterxml.uuid.impl.TimeBasedGenerator"
)
}
)
private UUID id; // 可排序的ID
}
场景2:安全敏感(如API密钥、令牌)
java
// 使用v4
public class ApiToken {
@Id
@GeneratedValue(generator = "uuid-v4")
@GenericGenerator(
name = "uuid-v4",
strategy = "org.hibernate.id.UUIDHexGenerator"
)
private UUID token; // 完全随机,更安全
}
场景3:分布式系统ID
java
// 结合使用(前缀+UUID)
public class DistributedIdGenerator {
public static String generateOrderId(String prefix) {
return prefix + "-" + UUID.randomUUID().toString().substring(0, 8);
}
// 示例: ORD-abc12345
}
总结建议
-
需要严格时间排序 → 使用 UUID v1 或 UUID v7
-
优点:自然按时间排序
-
缺点:v1可能泄露MAC地址,v7更安全
-
-
不需要时间排序 → 使用 UUID v4
-
优点:完全随机,安全性高
-
缺点:无法按生成时间排序
-
-
现代应用推荐 → UUID v7
-
结合了时间排序和安全性
-
但需要较新的库支持
-
-
数据库主键 → 考虑数据库性能
-
UUID作为主键可能影响索引性能
-
大表建议结合其他策略(如雪花算法)
-
选择时需平衡排序需求、安全性和性能要求。



2261

被折叠的 条评论
为什么被折叠?



