基于雪花算法实现的数据库唯一ID工具类

2023-12-15 11:40:24
package com.ideatech.ams.ucam.utils;

/**
 * Created with IntelliJ IDEA.
 * 用于生成唯一的数据库ID的工具类,基于雪花算法实现。
 * <p>
 * 雪花算法的特点:
 * - 时间有序:生成的ID随时间递增,保证了ID的时序性。
 * - 唯一性:在同一毫秒内生成的ID不会重复。
 * - 分布式友好:适用于分布式系统,避免ID冲突。
 * <p>
 * 使用方式:
 * 调用 generateUniqueId() 方法可以生成唯一的ID。
 * <p>
 * 注意事项:
 * - 需要确保系统时钟不回退,以避免生成的ID不连续。
 * - 在高并发情况下,需要测试生成的ID是否唯一。
 *
 * @author Gotham
 * @date 2023/9/23 Time: 15:41
 * Email: Gotham
 */
public class IdInitUtil {
    private static final long EPOCH = 1632360000000L; // 设置一个起始时间戳(2021-09-24)
    private static final long SEQUENCE_BITS = 12;
    private static final long MAX_SEQUENCE = (1L << SEQUENCE_BITS) - 1;
    private static final long SEQUENCE_SHIFT = 0;
    private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS;
    private static final long MAX_SEQUENCE_NUMBER = 999L; // 每毫秒最多生成999个ID

    private static long lastTimestamp = -1L;
    private static long sequence = 0L;

    /**
     * 生成数据库唯一ID方法
     *
     * @return 唯一ID
     * @throws RuntimeException 如果时钟回退或每毫秒生成的ID数量超过最大限制,将抛出异常
     */
    public synchronized static long generateUniqueId() {
        long currentTimestamp = System.currentTimeMillis();

        if (currentTimestamp < lastTimestamp) {
            throw new RuntimeException("时钟回退异常");
        }

        if (currentTimestamp == lastTimestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;

            if (sequence == 0) {
                // 当前毫秒内生成的ID超过最大限制
                currentTimestamp = waitUntilNextMillis(currentTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = currentTimestamp;

        long id = ((currentTimestamp - EPOCH) << TIMESTAMP_SHIFT) | (sequence << SEQUENCE_SHIFT);

        if (sequence > MAX_SEQUENCE_NUMBER) {
            throw new RuntimeException("每毫秒生成的ID数量超过最大限制");
        }

        return id;
    }

    /**
     * 生成数据库唯一ID方法
     *
     * @return 唯一ID
     * @throws RuntimeException 如果时钟回退或每毫秒生成的ID数量超过最大限制,将抛出异常
     */
    public synchronized static long generateNumber() {
        long currentTimestamp = System.currentTimeMillis();

        if (currentTimestamp < lastTimestamp) {
            throw new RuntimeException("时钟回退异常");
        }

        if (currentTimestamp == lastTimestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;

            if (sequence == 0) {
                // 当前毫秒内生成的ID超过最大限制
                currentTimestamp = waitUntilNextMillis(currentTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = currentTimestamp;

        long id = ((currentTimestamp - EPOCH) << TIMESTAMP_SHIFT) | (sequence << SEQUENCE_SHIFT);

        if (sequence > MAX_SEQUENCE_NUMBER) {
            throw new RuntimeException("每毫秒生成的ID数量超过最大限制");
        }

        return id;
    }

    /**
     * 在同一毫秒内等待,直到下一个毫秒
     *
     * @param currentTimestamp 当前时间戳
     * @return 下一个毫秒的时间戳
     */
    private static long waitUntilNextMillis(long currentTimestamp) {
        while (currentTimestamp <= lastTimestamp) {
            currentTimestamp = System.currentTimeMillis();
        }
        return currentTimestamp;
    }
}

文章来源:https://blog.csdn.net/qq_37707251/article/details/135012525
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。