Java中UUID生成原理及优缺点

 更新时间:2023年06月11日 10:54:09   作者:蜀山剑客李沐白  
本文将详细讲解UUID的生成原理、特性、实用场景以及优缺点,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

UUID 是一套用于生成全局唯一标识符的标准,也被称为 GUID (Globally Unique Identifier),通过使用 UUID 可以在分布式系统中生成唯一的 ID。UUID 的生成方式有多种,本文将详细讲解 UUID 的生成原理、特性、实用场景以及优缺点。

一、UUID 的生成原理

UUID 的英文全称为 Universally Unique Identifier,即通用唯一识别码,它是由一组 16 个字节(128 位)组成的标识符,可以用于唯一地标识信息。UUID 的生成方式有多种,其中最为常用的是基于算法的 UUID 生成方式和基于硬件的 UUID 生成方式。下面我们分别来介绍这两种生成方式的原理。

1. 基于算法的 UUID 生成方式

基于算法的 UUID 生成方式是指使用计算机程序根据一定的算法生成 UUID。这种方式的优点是可以在任何环境中生成 UUID,并且不需要依赖于任何硬件设备,缺点是生成的 UUID 不够随机,容易被猜测到,因此不适合用于安全领域。
目前最常用的基于算法的 UUID 生成方式是基于时间戳的 UUID 生成方式。该方式基于当前时间戳和机器的 MAC 地址生成 UUID,它的算法流程如下:

  • 获取当前时间戳和机器的 MAC 地址;
  • 将当前时间戳转换为 UTC 时间,并计算出自 1582 年 10 月 15 日午夜(即格林威治标准时间 0 点)以来的纳秒数,将其存储在 UUID 的时间戳字段中;
  • 将机器的 MAC 地址哈希得到其中的 6 个字节作为 UUID 的节点字段;
  • 随机生成两个字节作为 UUID 的时钟序列字段;
  • 将时间戳、节点、时钟序列等信息组合起来,生成 UUID。

基于时间戳的 UUID 生成方式可以保证在同一时刻生成的 UUID 唯一,并且可以提供一定的顺序性,因此非常适合用于分布式系统中对数据进行排序操作。但是,如果多台计算机的时钟存在差异,就有可能导致生成重复的 UUID,因此需要采取一些措施来防止时钟不同步的问题。此外,这种方式也容易受到时钟回拨攻击的影响,因此需要特殊处理。

2. 基于硬件的 UUID 生成方式

基于硬件的 UUID 生成方式是指使用计算机硬件设备生成 UUID,该方式的优点是生成的 UUID 随机性高,不容易被猜测到,缺点是只能在具备对应硬件设备的机器上生成 UUID,不够灵活。

基于硬件的 UUID 生成方式常用的有 MAC 地址 UUID 和 CPU ID UUID。

MAC 地址 UUID 是指使用计算机网卡设备的 MAC 地址作为 UUID 的节点字段,这种方式可以保证每个机器生成的 UUID 都是唯一的,并且不依赖于时钟同步。但是,它也存在一些缺点,比如计算机的网卡可能会被更换,导致 UUID 发生变化。

CPU ID UUID 是指使用计算机 CPU 的序列号作为 UUID 的节点字段,这种方式与 MAC 地址 UUID 很相似,但是比 MAC 地址 UUID 更加安全,因为 CPU 序列号不会轻易发生变化。不过,由于 CPU 可以被替换,因此这种方式也存在一定的风险。

二、UUID 的特性

UUID 具有以下几个特性:

1. 唯一性
UUID 是全局唯一的标识符,可以为分布式系统提供唯一的标识。

2. 随机性
UUID 的生成过程使用了随机性或伪随机性的元素,生成的 UUID 具有高度随机性,不容易被猜测到。

3. 不可推测性
UUID 是通过一定的算法生成的,生成的 UUID 不能从中推测出任何信息。

4. 可复制性
UUID 可以在不同的时间和地点被重复生成,但是在实践中,由于随机数的使用,重复的概率非常低。

5. 可比较性
UUID 是一个 128 位的二进制数字,可以进行比较操作,比较操作具有一定的顺序性。

三、UUID 的实用场景

由于 UUID 具有唯一性、随机性等特性,因此在很多应用场景中都得到了广泛的应用,下面列举几个典型的应用场景。

1. 数据库主键

在数据库中,每个记录都需要一个唯一的主键来区分,通常可以使用自增长 ID 作为主键。但是在分布式系统中,多个节点之间可能会产生 ID 冲突的问题。因此,可以使用 UUID 作为主键,确保每个记录的唯一性。

2. 分布式系统

在分布式系统中,需要将数据分布存储在多个节点上,并对数据进行全局唯一标识。这时可以使用 UUID 来为数据生成唯一的 ID,以便在整个系统中进行区分。

3. 日志跟踪

在分布式系统中,系统运行日志是监控和排查问题的重要依据。如果将日志中的每条记录都打上唯一的标识符,方便后期分析和跟踪。这时可以使用 UUID 来为日志记录生成唯一的 ID。

4. 安全领域

在安全领域中,需要为用户会话、密钥和证书等生成唯一的标识符,以保证安全性。这时可以使用 UUID 来生成唯一的标识符,确保不同对象之间的区分。

四、UUID 的优缺点

UUID 具有以下几个优点:

1. 全局唯一

UUID 可以为分布式系统提供全局唯一的标识符,避免了 ID 冲突的问题。

2. 可比较性

UUID 是一个数字,可以进行比较操作,具有一定的顺序性。

3. 无需中央协调机制

UUID 的生成不需要中央协调机制,因此可以在任何时间和地点生成 UUID。

4. 安全性高

UUID 的生成使用了随机性或伪随机性的元素,生成的 UUID 具有高度随机性,不容易被猜测到。因此可以在安全领域中使用。
但是,UUID 也具有以下几个缺点:

1. 占用空间大
UUID 是一个 128 位的二进制数字,占用的空间比较大,不适宜作为数据库主键使用。

2. 不易读懂
由于 UUID 是一个数字,因此不容易被人类读懂,不便于调试和排查问题。

3. 不适合顺序访问
UUID 的生成具有随机性,因此不适合对数据进行顺序访问操作。

4. 算法复杂
UUID 的生成算法比较复杂,在一定程度上影响了性能。

五、代码示例

import java.util.Random;
public class GenerateUUID {
    private static final long START_EPOCH = -12219292800000L;
    // 定义版本号和变体标识的位数
    private static final int VERSION_BITS = 4;
    private static final int VARIANT_BITS = 2;
    // 生成的 UUID 二进制形式共 128 位
    private static final int TOTAL_BITS = 128;
    public static void main(String[] args) {
        Random random = new Random();
        long timestamp = System.currentTimeMillis() + START_EPOCH;
        long leastSigBits = random.nextLong();
        long mostSigBits = random.nextLong();
        // 根据 RFC 4122 规范设置 UUID 版本号和变体标识
        mostSigBits &= ~(0xfL << 12); // 清空版本号
        mostSigBits |= (4L << 12); // 设置版本号
        leastSigBits &= ~(0x3L << 62); // 清空变体标识
        leastSigBits |= (0x2L << 62); // 设置变体标识
        // 将时间戳写入 UUID 中段
        long timeLow = timestamp & 0xffffffffL;
        long timeMid = (timestamp >> 32) & 0xffffL;
        long timeHiAndVersion = (timestamp >> 48) & 0x0fffL;
        mostSigBits &= ~(0xffffffffffffL << 64); // 清空时间戳
        mostSigBits |= (timeLow << 32);
        mostSigBits |= (timeMid << 16);
        mostSigBits |= timeHiAndVersion;
        // 构造 UUID 对象
        java.util.UUID uuid = new java.util.UUID(mostSigBits, leastSigBits);
        System.out.println(uuid.toString());
    }
}

上述代码中,我们首先使用 Random 类生成两个 64 位的伪随机数,分别作为 UUID 的高 64 位和低 64 位。然后,我们根据 RFC 4122 规范对 UUID 进行版本号标记和变体标识,并将当前时间戳的毫秒部分写入 UUID 的中段,以保证 UUID 具有一定的顺序性。最后,我们将生成的 UUID 的高 64 位和低 64 位传入 java.util.UUID 类的构造方法中,以创建一个 UUID 对象。

需要注意的是,由于我们在生成 UUID 的过程中使用了伪随机数,因此生成的 UUID 并不是真正的随机数,它们仅具有伪随机性。同时,由于我们没有保证时间戳的唯一性,因此同一时刻生成的 UUID 可能存在重复的风险。在实际应用中,我们通常建议使用 java.util.UUID.randomUUID() 方法生成 UUID。

六、总结

UUID 是一套用于生成全局唯一标识符的标准,具有唯一性、随机性等特性,可以在分布式系统中使用。UUID 的生成方式有多种,其中最为常用的是基于算法的 UUID 生成方式和基于硬件的 UUID 生成方式。UUID 在数据库主键、分布式系统、日志跟踪和安全领域等方面有广泛的应用。虽然 UUID 具有很多优点,但也存在一些缺点,比如占用空间大、不易读懂、不适合顺序访问和算法复杂等。综合来看,UUID 是一种非常有用的标识符生成方式,在实际开发中应根据具体情况选择合适的 UUID 生成方式。

到此这篇关于Java中UUID生成原理及优缺点的文章就介绍到这了,更多相关Java中UUID生成内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 如何在IDEA运行spark程序(搭建Spark开发环境)

    如何在IDEA运行spark程序(搭建Spark开发环境)

    spark程序可以通过pom.xml的文件配置,添加spark-core依赖,可以直接在IDEA中编写spark程序并运行结果,这篇文章主要介绍了如何在IDEA运行spark程序(搭建Spark开发环境),需要的朋友可以参考下
    2024-02-02
  • Java DOM4J方式生成XML的方法

    Java DOM4J方式生成XML的方法

    今天小编就为大家分享一篇Java DOM4J方式生成XML的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • 一文带你揭秘SpringMvc参数值映射

    一文带你揭秘SpringMvc参数值映射

    这篇文章主要给大家介绍了关于SpringMvc参数值映射的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-01-01
  • Spring JdbcTemplate执行数据库操作详解

    Spring JdbcTemplate执行数据库操作详解

    JdbcTemplate是Spring框架自带的对JDBC操作的封装,目的是提供统一的模板方法使对数据库的操作更加方便、友好,效率也不错,这篇文章主要介绍了Spring JdbcTemplate执行数据库操作,需要的朋友可以参考下
    2022-10-10
  • 如何在Java中使用WebSocket协议

    如何在Java中使用WebSocket协议

    WebSocket是一种基于 TCP 协议的全双工通信协议,可以在浏览器和服务器之间建立实时、双向的数据通信,下面这篇文章主要给大家介绍了关于如何在Java中使用WebSocket协议的相关资料,需要的朋友可以参考下
    2024-02-02
  • java实现幸运抽奖功能

    java实现幸运抽奖功能

    这篇文章主要为大家详细介绍了java实现幸运抽奖功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • Java实现拓扑排序的示例代码

    Java实现拓扑排序的示例代码

    这篇文章我们要讲的是拓扑排序,这是一个针对有向无环图的算法,主要是为了解决前驱后继的关系,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-05-05
  • MyBatis插入Insert、InsertSelective的区别及使用心得

    MyBatis插入Insert、InsertSelective的区别及使用心得

    这篇文章主要介绍了MyBatis插入Insert、InsertSelective的区别及使用心得,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • JAVA NIO按行读写大文件出现中文乱码问题的解决

    JAVA NIO按行读写大文件出现中文乱码问题的解决

    这篇文章主要为大家详细介绍了JAVA在使用NIO进行按行读写大文件时出现中文乱码问题是如何解决的,文中的示例代码简洁易懂,有需要的小伙伴可以参考一下
    2025-02-02
  • SpringBoot中MyBatis-Plus 查询时排除某些字段的操作方法

    SpringBoot中MyBatis-Plus 查询时排除某些字段的操作方法

    这篇文章主要介绍了SpringBoot中MyBatis-Plus 查询时排除某些字段的操作方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08

最新评论