您的位置:

Java UUID详解

UUID是通用唯一标识符的缩写,是一个软件构建的标准,它使用长度为128位(16字节)的值来表示信息。UUID可以保证对在同一时空中的所有机器都是唯一的,它实际上上是利用网络上的时间和计算机MAC地址来生成的。

一、UUID的优点

1、全球唯一性

    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
    System.out.println(uuid);

UUID采用128位编码,标识信息的唯一性,长时间不重复,保证了对于海量数据处理时,不会产生冲突。

2、无序性

    UUID uuid1 = UUID.randomUUID();
    UUID uuid2 = UUID.randomUUID();
    System.out.println(uuid1.compareTo(uuid2));

UUID采用无序性的编码,这个特性可以避免数据库在写入数据时,需要枷锁和解锁的操作,显著提升了开发效率。

3、方便存储和传输

    UUID uuid = UUID.randomUUID();
    ByteBuffer buffer = ByteBuffer.wrap(new byte[16]);
    buffer.putLong(uuid.getMostSignificantBits());
    buffer.putLong(uuid.getLeastSignificantBits());
    byte[] array = buffer.array();

UUID仅使用128位,方便对任意平台和数据库进行数据存储和传送。

二、UUID的使用

1、获取UUID

    UUID uuid = UUID.randomUUID();
    System.out.println(uuid.toString());

UUID类提供了randomUUID()方法,可以用于获取一个UUID对象。

2、UUID的表示

    UUID uuid = UUID.fromString("38400000-8cf0-11bd-b23e-10b96e4ef00d");
    System.out.println(uuid.getLeastSignificantBits());

通过fromString()方法可以将字符串转化成UUID对象,其中的连字符是可选的,但建议保留,这样可以方便读取。

3、UUID的比较

    UUID uuid1 = UUID.fromString("38400000-8cf0-11bd-b23e-10b96e4ef00d");
    UUID uuid2 = UUID.fromString("38400000-8cf0-11bd-b23e-10b96e4ef00d");
    System.out.println(uuid1.equals(uuid2));

UUID类提供了equals()、compareTo()等方法,用于比较两个UUID的大小是否相等,或者两个UUID是否相等,如果相等则返回0。

三、UUID生成算法

1、时间戳

    private static long toUnixTime(long timeStamp) {
        return (timeStamp - START_EPOCH) * 10000 + 0x01b21dd213814000L;
    }

    private static long timeToMillis(long time) {
        return (time - 0x01b21dd213814000L) / 10000 + START_EPOCH;
    }

    private static final long START_EPOCH;

    static {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        calendar.set(1582, Calendar.OCTOBER, 15, 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        START_EPOCH = calendar.getTimeInMillis();
    }

    private static long createTimestamp() {
        long timestamp = System.currentTimeMillis();
        long time = toUnixTime(timestamp);
        return time;
    }

UUID生成的过程中,会生成一个时间戳,通过时间戳可以保证生成的UUID在不同时间生成时不会重复。在Java中,可以使用System.currentTimeMillis()方法获取一个毫秒级别的时间戳。

2、MAC地址

    private static long createNode() {
        InetAddress address;
        try {
            address = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        }
        byte[] mac = null;
        try {
            mac = NetworkInterface.getByInetAddress(address).getHardwareAddress();
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }
        if (mac == null) {
            return 0xffffffffffffL;
        }
        long node = 0;
        for (int i = 0; i < mac.length; i++) {
            node |= ((long) mac[i] & 0xff) << (8 * (5 - i));
        }
        return node;
    }

UUID生成的过程中,还会用到机器的MAC地址,通过MAC地址可以保证生成的UUID在同一时间内,在不同机器上也不会重复。

3、随机数

    private static long createRandom() {
        SecureRandom random = new SecureRandom();
        byte[] bytes = new byte[8];
        random.nextBytes(bytes);
        return ((long) bytes[0] & 0xff) << 56 |
                ((long) bytes[1] & 0xff) << 48 |
                ((long) bytes[2] & 0xff) << 40 |
                ((long) bytes[3] & 0xff) << 32 |
                ((long) bytes[4] & 0xff) << 24 |
                ((long) bytes[5] & 0xff) << 16 |
                ((long) bytes[6] & 0xff) << 8 |
                ((long) bytes[7] & 0xff);
    }

UUID生成的过程中,还会用到随机数,通过随机数的存在,可以保证生成的UUID的唯一性。

四、UUID的应用场景

1、主键

在数据库中,通常将主键设计成UUID,可以避免业务层和数据层之间的耦合,更容易扩展。

2、文件名

在上传文件时,可以将文件名设置成UUID,可以避免出现重名文件,而且易于管理。

3、网络通信

在分布式系统中,可以使用UUID来定义一致的消息格式,方便不同系统之间的通信。

五、总结

UUID是一个通用唯一标识符,具有全球唯一性、无序性、方便传输等优点,可以应用于主键、文件名、网络通信等场景。UUID的生成需要时间戳、MAC地址和随机数的支持,可以采用UUID类提供的方法获取UUID对象,也可以自己编写生成算法。