UUID 的生成示例

前端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()

  1. 关于 crypto 对象
    crypto 是一个全局的内置对象,它提供了密码学相关的基础功能。这个对象不是第三方库,而是 Web 标准(Web Crypto API)的一部分,由浏览器或 Node.js 运行时原生提供,因此非常可靠且性能优异。

  2. 关于 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
}

总结建议

  1. 需要严格时间排序 → 使用 UUID v1 或 UUID v7

    • 优点:自然按时间排序

    • 缺点:v1可能泄露MAC地址,v7更安全

  2. 不需要时间排序 → 使用 UUID v4

    • 优点:完全随机,安全性高

    • 缺点:无法按生成时间排序

  3. 现代应用推荐 → UUID v7

    • 结合了时间排序和安全性

    • 但需要较新的库支持

  4. 数据库主键 → 考虑数据库性能

    • UUID作为主键可能影响索引性能

    • 大表建议结合其他策略(如雪花算法)

选择时需平衡排序需求、安全性和性能要求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值