欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot集成雪花算法唯一ID的實(shí)現(xiàn)

 更新時(shí)間:2025年09月16日 09:45:19   作者:柯南二號  
本文主要介紹了SpringBoot集成雪花算法唯一ID的實(shí)現(xiàn),適用于高并發(fā)與分庫分表場景,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

在分布式系統(tǒng)中,我們經(jīng)常需要生成 全局唯一 ID,比如用戶 ID、訂單號、消息 ID 等。常見的方式有:數(shù)據(jù)庫自增主鍵、UUID、Redis/Zookeeper 分布式 ID 服務(wù)、百度 UidGenerator、美團(tuán) Leaf 等。

其中,Twitter 的雪花算法(Snowflake) 是一種輕量級、高性能的分布式唯一 ID 解決方案,被廣泛使用。本文將帶你在 Spring Boot 中實(shí)現(xiàn)并集成雪花算法。

一、為什么需要雪花算法?

  1. 數(shù)據(jù)庫自增 ID

    • 簡單,但在分庫分表和分布式場景下會(huì)產(chǎn)生沖突。

  2. UUID

    • 全球唯一,但字符串太長(36 位),不適合做數(shù)據(jù)庫索引。

  3. 雪花算法(Snowflake)

    • 生成 64 位 long 型 ID,趨勢遞增,性能高,適合分布式環(huán)境。

二、雪花算法原理

Snowflake 算法會(huì)生成一個(gè) 64 bit 的 long 型整數(shù),格式如下:

| 1位符號位(始終為0) | 41位時(shí)間戳 | 5位數(shù)據(jù)中心ID | 5位機(jī)器ID | 12位序列號 |
  • 符號位:始終為 0,保證 ID 為正數(shù)。
  • 時(shí)間戳:當(dāng)前毫秒時(shí)間戳 - 起始時(shí)間戳,可用約 69 年。
  • 數(shù)據(jù)中心 ID:范圍 0~31,可支持 32 個(gè)數(shù)據(jù)中心。
  • 機(jī)器 ID:范圍 0~31,每個(gè)數(shù)據(jù)中心支持 32 臺機(jī)器。
  • 序列號:范圍 0~4095,每毫秒可生成 4096 個(gè)唯一 ID。

三、Spring Boot 實(shí)現(xiàn)雪花算法

1. 創(chuàng)建工具類SnowflakeIdGenerator

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * 雪花算法ID生成器
 * 
 * 雪花算法生成的ID結(jié)構(gòu):
 * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
 * 1位符號位 + 41位時(shí)間戳 + 5位數(shù)據(jù)中心ID + 5位機(jī)器ID + 12位序列號 = 64位
 * 
 * 特點(diǎn):
 * - 生成的ID趨勢遞增
 * - 整個(gè)分布式系統(tǒng)內(nèi)不會(huì)產(chǎn)生重復(fù)ID
 * - 能夠根據(jù)時(shí)間戳排序
 * - 每毫秒能夠生成4096個(gè)ID
 */
@Component
public class SnowflakeIdGenerator {

    /**
     * 起始時(shí)間戳 (2024-01-01 00:00:00)
     * 可以使用約69年
     */
    private static final long START_TIMESTAMP = 1704067200000L;

    /**
     * 數(shù)據(jù)中心ID位數(shù)
     */
    private static final long DATACENTER_ID_BITS = 5L;

    /**
     * 機(jī)器ID位數(shù)
     */
    private static final long MACHINE_ID_BITS = 5L;

    /**
     * 序列號位數(shù)
     */
    private static final long SEQUENCE_BITS = 12L;

    /**
     * 數(shù)據(jù)中心ID最大值 (2^5 - 1 = 31)
     */
    private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS);

    /**
     * 機(jī)器ID最大值 (2^5 - 1 = 31)
     */
    private static final long MAX_MACHINE_ID = ~(-1L << MACHINE_ID_BITS);

    /**
     * 序列號最大值 (2^12 - 1 = 4095)
     */
    private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);

    /**
     * 機(jī)器ID左移位數(shù)
     */
    private static final long MACHINE_ID_SHIFT = SEQUENCE_BITS;

    /**
     * 數(shù)據(jù)中心ID左移位數(shù)
     */
    private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS;

    /**
     * 時(shí)間戳左移位數(shù)
     */
    private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS + DATACENTER_ID_BITS;

    /**
     * 數(shù)據(jù)中心ID
     */
    private final long datacenterId;

    /**
     * 機(jī)器ID
     */
    private final long machineId;

    /**
     * 序列號
     */
    private long sequence = 0L;

    /**
     * 上次生成ID的時(shí)間戳
     */
    private long lastTimestamp = -1L;

    /**
     * 構(gòu)造函數(shù)
     */
    public SnowflakeIdGenerator(
            @Value("${snowflake.datacenter-id:1}") long datacenterId,
            @Value("${snowflake.machine-id:1}") long machineId) {
        
        if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {
            throw new IllegalArgumentException(
                String.format("數(shù)據(jù)中心ID必須在0-%d之間", MAX_DATACENTER_ID));
        }
        
        if (machineId > MAX_MACHINE_ID || machineId < 0) {
            throw new IllegalArgumentException(
                String.format("機(jī)器ID必須在0-%d之間", MAX_MACHINE_ID));
        }
        
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    /**
     * 生成下一個(gè)ID
     * 
     * @return 唯一ID
     */
    public synchronized long nextId() {
        long timestamp = getCurrentTimestamp();

        // 如果當(dāng)前時(shí)間小于上一次ID生成的時(shí)間戳,說明系統(tǒng)時(shí)鐘回退過,拋出異常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                String.format("系統(tǒng)時(shí)鐘回退,拒絕生成ID。時(shí)鐘回退了%d毫秒", lastTimestamp - timestamp));
        }

        // 如果是同一時(shí)間生成的,則進(jìn)行毫秒內(nèi)序列
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            // 毫秒內(nèi)序列溢出,等待下一毫秒
            if (sequence == 0) {
                timestamp = getNextTimestamp(lastTimestamp);
            }
        } else {
            // 時(shí)間戳改變,毫秒內(nèi)序列重置
            sequence = 0L;
        }

        // 上次生成ID的時(shí)間戳
        lastTimestamp = timestamp;

        // 移位并通過或運(yùn)算拼到一起組成64位的ID
        return ((timestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)
                | (datacenterId << DATACENTER_ID_SHIFT)
                | (machineId << MACHINE_ID_SHIFT)
                | sequence;
    }

    /**
     * 生成字符串格式的ID
     * 
     * @return 字符串ID
     */
    public String nextIdStr() {
        return String.valueOf(nextId());
    }

    /**
     * 解析ID獲取生成時(shí)間
     * 
     * @param id 雪花ID
     * @return 生成時(shí)間戳
     */
    public long parseTimestamp(long id) {
        return (id >> TIMESTAMP_SHIFT) + START_TIMESTAMP;
    }

    /**
     * 解析ID獲取數(shù)據(jù)中心ID
     * 
     * @param id 雪花ID
     * @return 數(shù)據(jù)中心ID
     */
    public long parseDatacenterId(long id) {
        return (id >> DATACENTER_ID_SHIFT) & MAX_DATACENTER_ID;
    }

    /**
     * 解析ID獲取機(jī)器ID
     * 
     * @param id 雪花ID
     * @return 機(jī)器ID
     */
    public long parseMachineId(long id) {
        return (id >> MACHINE_ID_SHIFT) & MAX_MACHINE_ID;
    }

    /**
     * 解析ID獲取序列號
     * 
     * @param id 雪花ID
     * @return 序列號
     */
    public long parseSequence(long id) {
        return id & MAX_SEQUENCE;
    }

    /**
     * 獲取當(dāng)前時(shí)間戳
     * 
     * @return 當(dāng)前時(shí)間戳
     */
    private long getCurrentTimestamp() {
        return System.currentTimeMillis();
    }

    /**
     * 獲取下一毫秒時(shí)間戳
     * 
     * @param lastTimestamp 上次時(shí)間戳
     * @return 下一毫秒時(shí)間戳
     */
    private long getNextTimestamp(long lastTimestamp) {
        long timestamp = getCurrentTimestamp();
        while (timestamp <= lastTimestamp) {
            timestamp = getCurrentTimestamp();
        }
        return timestamp;
    }

    /**
     * 獲取生成器信息
     * 
     * @return 生成器信息
     */
    public String getGeneratorInfo() {
        return String.format("SnowflakeIdGenerator[datacenterId=%d, machineId=%d]", 
                           datacenterId, machineId);
    }
}

2. 在 Spring Boot 中配置 Bean

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * ID生成工具類
 * 提供靜態(tài)方法方便調(diào)用
 */
@Component
public class IdUtils {

    @Autowired
    private SnowflakeIdGenerator snowflakeIdGenerator;

    private static SnowflakeIdGenerator staticSnowflakeIdGenerator;
    
    // 靜態(tài)初始化,確保在沒有Spring容器時(shí)也能工作
    static {
        if (staticSnowflakeIdGenerator == null) {
            staticSnowflakeIdGenerator = new SnowflakeIdGenerator(1, 1);
        }
    }

    @PostConstruct
    public void init() {
        if (snowflakeIdGenerator != null) {
            staticSnowflakeIdGenerator = snowflakeIdGenerator;
        }
    }

    /**
     * 生成雪花算法ID
     * 
     * @return 唯一ID
     */
    public static long generateId() {
        return staticSnowflakeIdGenerator.nextId();
    }

    /**
     * 生成雪花算法ID字符串
     * 
     * @return 唯一ID字符串
     */
    public static String generateIdStr() {
        return staticSnowflakeIdGenerator.nextIdStr();
    }

    /**
     * 解析ID獲取生成時(shí)間
     * 
     * @param id 雪花ID
     * @return 生成時(shí)間戳
     */
    public static long parseTimestamp(long id) {
        return staticSnowflakeIdGenerator.parseTimestamp(id);
    }

    /**
     * 解析ID獲取數(shù)據(jù)中心ID
     * 
     * @param id 雪花ID
     * @return 數(shù)據(jù)中心ID
     */
    public static long parseDatacenterId(long id) {
        return staticSnowflakeIdGenerator.parseDatacenterId(id);
    }

    /**
     * 解析ID獲取機(jī)器ID
     * 
     * @param id 雪花ID
     * @return 機(jī)器ID
     */
    public static long parseMachineId(long id) {
        return staticSnowflakeIdGenerator.parseMachineId(id);
    }

    /**
     * 解析ID獲取序列號
     * 
     * @param id 雪花ID
     * @return 序列號
     */
    public static long parseSequence(long id) {
        return staticSnowflakeIdGenerator.parseSequence(id);
    }

    /**
     * 獲取生成器信息
     * 
     * @return 生成器信息
     */
    public static String getGeneratorInfo() {
        return staticSnowflakeIdGenerator.getGeneratorInfo();
    }
}

3. 測試工具類

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 簡單的雪花算法測試工具
 * 獨(dú)立運(yùn)行,不依賴Spring容器
 */
public class SimpleSnowflakeTest {
    
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    
    public static void main(String[] args) {
        System.out.println("=== 雪花算法ID生成器簡單測試 ===\n");
        
        // 創(chuàng)建生成器實(shí)例
        SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);
        
        // 顯示配置信息
        showInfo(generator);
        
        // 基礎(chǔ)功能測試
        testBasicGeneration(generator);
        
        // 批量生成測試
        testBatchGeneration(generator);
        
        // 性能測試
        testPerformance(generator);
        
        // 唯一性測試
        testUniqueness(generator);
        
        // 遞增性測試
        testIncrement(generator);
        
        System.out.println("\n=== 測試完成 ===");
    }
    
    /**
     * 顯示配置信息
     */
    private static void showInfo(SnowflakeIdGenerator generator) {
        System.out.println("?? 配置信息:");
        System.out.println("  數(shù)據(jù)中心ID: 1");
        System.out.println("  機(jī)器ID: 1");
        System.out.println("  當(dāng)前時(shí)間: " + LocalDateTime.now().format(FORMATTER));
        System.out.println();
    }
    
    /**
     * 基礎(chǔ)ID生成測試
     */
    private static void testBasicGeneration(SnowflakeIdGenerator generator) {
        System.out.println("?? 基礎(chǔ)ID生成測試:");
        
        // 生成單個(gè)ID
        long id1 = generator.nextId();
        System.out.println("  單個(gè)ID: " + id1);
        
        // 連續(xù)生成幾個(gè)ID
        System.out.println("  連續(xù)生成5個(gè)ID:");
        for (int i = 0; i < 5; i++) {
            long id = generator.nextId();
            System.out.println("    ID " + (i + 1) + ": " + id);
        }
        System.out.println();
    }
    
    /**
     * 批量生成測試
     */
    private static void testBatchGeneration(SnowflakeIdGenerator generator) {
        System.out.println("?? 批量生成測試:");
        
        int count = 10;
        List<Long> ids = new ArrayList<>();
        
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            ids.add(generator.nextId());
        }
        long endTime = System.currentTimeMillis();
        
        System.out.println("  生成 " + count + " 個(gè)ID耗時(shí): " + (endTime - startTime) + "ms");
        System.out.println("  生成的ID:");
        for (int i = 0; i < ids.size(); i++) {
            System.out.println("    " + (i + 1) + ": " + ids.get(i));
        }
        System.out.println();
    }
    
    /**
     * 性能測試
     */
    private static void testPerformance(SnowflakeIdGenerator generator) {
        System.out.println("? 性能測試:");
        
        int testCount = 100000;
        
        System.out.println("  單線程性能測試 (" + testCount + " 個(gè)ID):");
        long startTime = System.currentTimeMillis();
        
        for (int i = 0; i < testCount; i++) {
            generator.nextId();
        }
        
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;
        double avgTimePerId = (double) duration / testCount;
        double idsPerSecond = testCount * 1000.0 / duration;
        
        System.out.println("    總耗時(shí): " + duration + "ms");
        System.out.println("    平均每個(gè)ID: " + String.format("%.4f", avgTimePerId) + "ms");
        System.out.println("    每秒生成: " + String.format("%.0f", idsPerSecond) + " 個(gè)ID");
        System.out.println();
    }
    
    /**
     * 唯一性測試
     */
    private static void testUniqueness(SnowflakeIdGenerator generator) {
        System.out.println("?? 唯一性測試:");
        
        int testCount = 100000;
        Set<Long> ids = ConcurrentHashMap.newKeySet();
        
        long startTime = System.currentTimeMillis();
        
        for (int i = 0; i < testCount; i++) {
            Long id = generator.nextId();
            ids.add(id);
        }
        
        long endTime = System.currentTimeMillis();
        
        System.out.println("  生成ID數(shù)量: " + testCount);
        System.out.println("  唯一ID數(shù)量: " + ids.size());
        System.out.println("  唯一性測試: " + (ids.size() == testCount ? "? 通過" : "? 失敗"));
        System.out.println("  測試耗時(shí): " + (endTime - startTime) + "ms");
        System.out.println();
    }
    
    /**
     * 遞增性測試
     */
    private static void testIncrement(SnowflakeIdGenerator generator) {
        System.out.println("?? 遞增性測試:");
        
        int testCount = 100;
        List<Long> ids = new ArrayList<>();
        
        // 生成測試ID
        for (int i = 0; i < testCount; i++) {
            ids.add(generator.nextId());
        }
        
        // 檢查遞增性
        boolean isIncreasing = true;
        int nonIncreasingCount = 0;
        
        for (int i = 1; i < ids.size(); i++) {
            if (ids.get(i) <= ids.get(i - 1)) {
                isIncreasing = false;
                nonIncreasingCount++;
            }
        }
        
        System.out.println("  測試ID數(shù)量: " + testCount);
        System.out.println("  遞增性測試: " + (isIncreasing ? "? 通過" : "? 失敗"));
        if (!isIncreasing) {
            System.out.println("  非遞增數(shù)量: " + nonIncreasingCount);
        }
        
        // 顯示前幾個(gè)和后幾個(gè)ID
        System.out.println("  前5個(gè)ID:");
        for (int i = 0; i < Math.min(5, ids.size()); i++) {
            System.out.println("    " + (i + 1) + ": " + ids.get(i));
        }
        
        if (ids.size() > 5) {
            System.out.println("  后5個(gè)ID:");
            for (int i = ids.size() - 5; i < ids.size(); i++) {
                System.out.println("    " + (i + 1) + ": " + ids.get(i));
            }
        }
        System.out.println();
    }
    
    /**
     * 演示ID解析功能
     */
    private static void testIdParsing() {
        System.out.println("?? ID解析測試:");
        
        // 創(chuàng)建生成器
        SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);
        Long testId = generator.nextId();
        
        System.out.println("  測試ID: " + testId);
        
        // 解析ID的各個(gè)部分
        long timestamp = IdUtils.parseTimestamp(testId);
        long datacenterId = IdUtils.parseDatacenterId(testId);
        long machineId = IdUtils.parseMachineId(testId);
        long sequence = IdUtils.parseSequence(testId);
        
        LocalDateTime generatedTime = LocalDateTime.ofInstant(
            java.time.Instant.ofEpochMilli(timestamp), 
            java.time.ZoneId.systemDefault()
        );
        
        System.out.println("  解析結(jié)果:");
        System.out.println("    時(shí)間戳: " + timestamp);
        System.out.println("    生成時(shí)間: " + generatedTime.format(FORMATTER));
        System.out.println("    數(shù)據(jù)中心ID: " + datacenterId);
        System.out.println("    機(jī)器ID: " + machineId);
        System.out.println("    序列號: " + sequence);
        
        // 計(jì)算ID生成到現(xiàn)在的時(shí)間差
        long age = System.currentTimeMillis() - timestamp;
        System.out.println("    ID年齡: " + age + "ms");
        System.out.println();
    }
    
    /**
     * 演示不同配置的生成器
     */
    private static void testDifferentConfigurations() {
        System.out.println("??  不同配置測試:");
        
        // 創(chuàng)建不同配置的生成器
        SnowflakeIdGenerator generator1 = new SnowflakeIdGenerator(1, 1);
        SnowflakeIdGenerator generator2 = new SnowflakeIdGenerator(1, 2);
        SnowflakeIdGenerator generator3 = new SnowflakeIdGenerator(2, 1);
        
        System.out.println("  數(shù)據(jù)中心1-機(jī)器1: " + generator1.nextId());
        System.out.println("  數(shù)據(jù)中心1-機(jī)器2: " + generator2.nextId());
        System.out.println("  數(shù)據(jù)中心2-機(jī)器1: " + generator3.nextId());
        System.out.println();
    }
}

直接運(yùn)行

4. 在業(yè)務(wù)中使用

import com.example.common.util.IdUtils;
import com.example.common.util.SnowflakeIdGenerator;
import com.example.common.web.ApiResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ID生成控制器
 * 提供雪花算法ID的生成和解析服務(wù)
 */
@RestController
@RequestMapping("/common/id")
@Api(tags = "ID生成服務(wù)")
public class IdController {

    @Autowired
    private SnowflakeIdGenerator snowflakeIdGenerator;

    /**
     * 生成單個(gè)雪花算法ID
     */
    @GetMapping("/generate")
    @ApiOperation("生成單個(gè)雪花算法ID")
    public ApiResponse<Map<String, Object>> generateId() {
        long id = IdUtils.generateId();
        
        Map<String, Object> result = new HashMap<>();
        result.put("id", id);
        result.put("idStr", String.valueOf(id));
        result.put("timestamp", System.currentTimeMillis());
        result.put("generatedAt", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        
        return ApiResponse.success(result);
    }

    /**
     * 生成字符串格式的雪花算法ID
     */
    @GetMapping("/generate/string")
    @ApiOperation("生成字符串格式的雪花算法ID")
    public ApiResponse<Map<String, Object>> generateIdString() {
        String idStr = IdUtils.generateIdStr();
        
        Map<String, Object> result = new HashMap<>();
        result.put("idStr", idStr);
        result.put("id", Long.parseLong(idStr));
        result.put("timestamp", System.currentTimeMillis());
        result.put("generatedAt", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        
        return ApiResponse.success(result);
    }

    /**
     * 批量生成雪花算法ID
     */
    @GetMapping("/generate/batch")
    @ApiOperation("批量生成雪花算法ID")
    public ApiResponse<Map<String, Object>> generateBatchIds(
            @ApiParam("生成數(shù)量,最大100") @RequestParam(defaultValue = "10") int count) {
        
        if (count <= 0 || count > 100) {
            return ApiResponse.error(400, "生成數(shù)量必須在1-100之間");
        }
        
        List<Long> ids = new ArrayList<>();
        List<String> idStrs = new ArrayList<>();
        
        for (int i = 0; i < count; i++) {
            long id = IdUtils.generateId();
            ids.add(id);
            idStrs.add(String.valueOf(id));
        }
        
        Map<String, Object> result = new HashMap<>();
        result.put("count", count);
        result.put("ids", ids);
        result.put("idStrs", idStrs);
        result.put("timestamp", System.currentTimeMillis());
        result.put("generatedAt", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        
        return ApiResponse.success(result);
    }

    /**
     * 解析雪花算法ID
     */
    @GetMapping("/parse/{id}")
    @ApiOperation("解析雪花算法ID")
    public ApiResponse<Map<String, Object>> parseId(
            @ApiParam("要解析的雪花算法ID") @PathVariable Long id) {
        
        try {
            long timestamp = IdUtils.parseTimestamp(id);
            long datacenterId = IdUtils.parseDatacenterId(id);
            long machineId = IdUtils.parseMachineId(id);
            long sequence = IdUtils.parseSequence(id);
            
            LocalDateTime generatedTime = LocalDateTime.ofInstant(
                Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
            
            Map<String, Object> result = new HashMap<>();
            result.put("originalId", id);
            result.put("originalIdStr", String.valueOf(id));
            result.put("timestamp", timestamp);
            result.put("generatedTime", generatedTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            result.put("datacenterId", datacenterId);
            result.put("machineId", machineId);
            result.put("sequence", sequence);
            
            // 計(jì)算ID生成到現(xiàn)在的時(shí)間差
            long timeDiff = System.currentTimeMillis() - timestamp;
            result.put("ageMs", timeDiff);
            result.put("ageSeconds", timeDiff / 1000);
            result.put("ageMinutes", timeDiff / (1000 * 60));
            
            return ApiResponse.success(result);
            
        } catch (Exception e) {
            return ApiResponse.error(400, "無效的雪花算法ID: " + e.getMessage());
        }
    }

    /**
     * 批量解析雪花算法ID
     */
    @PostMapping("/parse/batch")
    @ApiOperation("批量解析雪花算法ID")
    public ApiResponse<Map<String, Object>> parseBatchIds(
            @ApiParam("要解析的ID列表") @RequestBody List<Long> ids) {
        
        if (ids == null || ids.isEmpty()) {
            return ApiResponse.error(400, "ID列表不能為空");
        }
        
        if (ids.size() > 50) {
            return ApiResponse.error(400, "一次最多解析50個(gè)ID");
        }
        
        List<Map<String, Object>> results = new ArrayList<>();
        List<String> errors = new ArrayList<>();
        
        for (Long id : ids) {
            try {
                long timestamp = IdUtils.parseTimestamp(id);
                long datacenterId = IdUtils.parseDatacenterId(id);
                long machineId = IdUtils.parseMachineId(id);
                long sequence = IdUtils.parseSequence(id);
                
                LocalDateTime generatedTime = LocalDateTime.ofInstant(
                    Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
                
                Map<String, Object> result = new HashMap<>();
                result.put("originalId", id);
                result.put("timestamp", timestamp);
                result.put("generatedTime", generatedTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                result.put("datacenterId", datacenterId);
                result.put("machineId", machineId);
                result.put("sequence", sequence);
                
                results.add(result);
                
            } catch (Exception e) {
                errors.add("ID " + id + " 解析失敗: " + e.getMessage());
            }
        }
        
        Map<String, Object> response = new HashMap<>();
        response.put("totalCount", ids.size());
        response.put("successCount", results.size());
        response.put("errorCount", errors.size());
        response.put("results", results);
        
        if (!errors.isEmpty()) {
            response.put("errors", errors);
        }
        
        return ApiResponse.success(response);
    }

    /**
     * 獲取ID生成器信息
     */
    @GetMapping("/info")
    @ApiOperation("獲取ID生成器信息")
    public ApiResponse<Map<String, Object>> getGeneratorInfo() {
        String generatorInfo = IdUtils.getGeneratorInfo();
        
        // 生成一個(gè)示例ID用于展示
        long sampleId = IdUtils.generateId();
        
        Map<String, Object> result = new HashMap<>();
        result.put("generatorInfo", generatorInfo);
        result.put("sampleId", sampleId);
        result.put("sampleIdStr", String.valueOf(sampleId));
        result.put("currentTimestamp", System.currentTimeMillis());
        result.put("currentTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        
        // 添加雪花算法的基本信息
        Map<String, Object> algorithmInfo = new HashMap<>();
        algorithmInfo.put("name", "Snowflake Algorithm");
        algorithmInfo.put("totalBits", 64);
        algorithmInfo.put("timestampBits", 41);
        algorithmInfo.put("datacenterIdBits", 5);
        algorithmInfo.put("machineIdBits", 5);
        algorithmInfo.put("sequenceBits", 12);
        algorithmInfo.put("maxDatacenterId", 31);
        algorithmInfo.put("maxMachineId", 31);
        algorithmInfo.put("maxSequence", 4095);
        algorithmInfo.put("maxIdsPerMs", 4096);
        algorithmInfo.put("maxIdsPerSecond", 4096000);
        
        result.put("algorithmInfo", algorithmInfo);
        
        return ApiResponse.success(result);
    }

    /**
     * 健康檢查 - 測試ID生成性能
     */
    @GetMapping("/health")
    @ApiOperation("ID生成器健康檢查")
    public ApiResponse<Map<String, Object>> healthCheck() {
        try {
            long startTime = System.currentTimeMillis();
            
            // 生成100個(gè)ID測試性能
            List<Long> testIds = new ArrayList<>();
            for (int i = 0; i < 100; i++) {
                testIds.add(IdUtils.generateId());
            }
            
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            
            // 驗(yàn)證ID的唯一性
            long distinctCount = testIds.stream().distinct().count();
            boolean isUnique = distinctCount == testIds.size();
            
            // 驗(yàn)證ID的遞增性
            boolean isIncreasing = true;
            for (int i = 1; i < testIds.size(); i++) {
                if (testIds.get(i) <= testIds.get(i - 1)) {
                    isIncreasing = false;
                    break;
                }
            }
            
            Map<String, Object> result = new HashMap<>();
            result.put("status", "healthy");
            result.put("testCount", 100);
            result.put("durationMs", duration);
            result.put("avgTimePerIdMs", duration / 100.0);
            result.put("idsPerSecond", Math.round(100000.0 / duration));
            result.put("uniqueIds", isUnique);
            result.put("increasingOrder", isIncreasing);
            result.put("firstId", testIds.get(0));
            result.put("lastId", testIds.get(testIds.size() - 1));
            result.put("checkTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            
            return ApiResponse.success(result);
            
        } catch (Exception e) {
            Map<String, Object> result = new HashMap<>();
            result.put("status", "unhealthy");
            result.put("error", e.getMessage());
            result.put("checkTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            
            return ApiResponse.error(500, "ID生成器健康檢查失敗", result);
        }
    }
}

啟動(dòng)項(xiàng)目后,訪問:

http://localhost:8080/common/id/generate

{
  "code": 200,
  "message": "操作成功",
  "data": {
    "idStr": "225614442879127552",
    "generatedAt": "2025-09-14 21:51:14",
    "id": 225614442879127550,
    "timestamp": 1757857874896
  },
  "timestamp": 1757857874896
}

就能得到一個(gè) 分布式唯一 ID

四、雪花算法的優(yōu)缺點(diǎn)

? 優(yōu)點(diǎn)

  • 本地生成 ID,高性能、低延遲。
  • 64 位 long 型,適合數(shù)據(jù)庫主鍵,索引效率高。
  • 趨勢遞增,分庫分表更友好。

?? 缺點(diǎn)

  • 時(shí)間回?fù)軉栴}:如果系統(tǒng)時(shí)間被調(diào)回,可能導(dǎo)致 ID 重復(fù)。
  • workerId 配置:需要保證每臺機(jī)器的 workerId 唯一,否則會(huì)沖突。
  • 單機(jī)生成上限:每毫秒 4096 個(gè) ID,極端場景可能不夠。

五、適用場景

  • 用戶 ID、訂單號、消息 ID 等需要分布式唯一 ID 的場景。
  • 高并發(fā)系統(tǒng)中需要性能高、趨勢遞增的 ID。
  • 分庫分表需要按 ID 范圍路由的系統(tǒng)。

六、分布式唯一 ID 生成方案對比

在分布式系統(tǒng)中,唯一 ID 是最基礎(chǔ)的需求。常見的實(shí)現(xiàn)方式有以下幾類:

1. 數(shù)據(jù)庫自增 ID

原理:依賴數(shù)據(jù)庫主鍵自增特性(AUTO_INCREMENT / Sequence)。

優(yōu)點(diǎn)

  • 實(shí)現(xiàn)簡單,無需額外服務(wù)。
  • ID 有序,方便分頁與索引。

缺點(diǎn)

  • 單庫有性能瓶頸,QPS 不高。
  • 擴(kuò)展到分布式場景需要分庫分表,增加復(fù)雜性。

適用場景:小型項(xiàng)目、單體應(yīng)用。

2. UUID / GUID

原理:基于隨機(jī)數(shù)、MAC 地址和時(shí)間戳生成 128 位 ID。

優(yōu)點(diǎn)

  • 本地生成,無需依賴第三方服務(wù)。
  • 全球唯一,沖突概率極低。

缺點(diǎn)

  • 長度過長(16 字節(jié) / 36 字符),存儲(chǔ)和索引性能差。
  • 無序,不利于數(shù)據(jù)庫分頁與索引。

適用場景:日志追蹤、分布式追蹤、無需排序的業(yè)務(wù)。

3. Redis INCR

原理:利用 Redis 的原子自增操作生成 ID。

優(yōu)點(diǎn)

  • 高并發(fā)下性能優(yōu)秀。
  • 簡單易用,支持多節(jié)點(diǎn)共享。

缺點(diǎn)

  • 依賴 Redis,高可用需額外維護(hù)。
  • 擴(kuò)展性依賴 Redis 集群。

適用場景:電商訂單號、消息序列號。

4. Twitter Snowflake

原理:使用 64 位二進(jìn)制結(jié)構(gòu)(時(shí)間戳 + 數(shù)據(jù)中心 ID + 機(jī)器 ID + 序列號)。

優(yōu)點(diǎn)

  • 高性能,本地生成,不依賴數(shù)據(jù)庫。
  • 數(shù)字型,長度適中,遞增趨勢。

缺點(diǎn)

  • 需要合理分配數(shù)據(jù)中心和機(jī)器 ID。
  • 對系統(tǒng)時(shí)鐘依賴強(qiáng),時(shí)鐘回?fù)軙?huì)導(dǎo)致重復(fù) ID。

適用場景:高并發(fā)系統(tǒng)(訂單 ID、日志 ID、分布式唯一標(biāo)識)。

5. Zookeeper 分布式 ID

原理:利用 Zookeeper 順序節(jié)點(diǎn)特性生成 ID。

優(yōu)點(diǎn)

  • 強(qiáng)一致性,保證全局唯一遞增。

缺點(diǎn)

  • 性能一般,QPS 不高。
  • 依賴 Zookeeper 集群,運(yùn)維成本高。

適用場景:金融業(yè)務(wù)、分布式鎖、強(qiáng)一致性場景。

6. 百度 UidGenerator

原理:基于 Snowflake 改造,支持時(shí)間回?fù)芴幚?,依賴?shù)據(jù)庫分配 WorkerID。

優(yōu)點(diǎn)

  • 高性能,單機(jī) QPS 可達(dá) 600 萬。
  • 支持秒級、分級、時(shí)級時(shí)間單位,靈活。

缺點(diǎn)

  • 依賴數(shù)據(jù)庫分配 WorkerID。
  • 社區(qū)活躍度一般,維護(hù)較少。

適用場景:高并發(fā)業(yè)務(wù)(訂單、交易流水、日志 ID)。

7. 美團(tuán) Leaf

原理:提供兩種模式:

  • Segment 模式:基于數(shù)據(jù)庫號段。
  • Snowflake 模式:本地生成。

優(yōu)點(diǎn)

  • 雙模式保證高可用(DB + Snowflake)。
  • 經(jīng)過美團(tuán)生產(chǎn)驗(yàn)證,穩(wěn)定可靠。
  • Leaf-Snowflake 支持 ZooKeeper 進(jìn)行 WorkerID 分配,避免沖突。

缺點(diǎn)

  • 系統(tǒng)復(fù)雜度較高。
  • 部署依賴 ZooKeeper 或數(shù)據(jù)庫。

適用場景:大規(guī)模分布式系統(tǒng)(訂單 ID、交易號、日志流水號)。

總結(jié)對比表

方案長度順序性依賴組件性能 (QPS)復(fù)雜度適用場景
數(shù)據(jù)庫自增 ID有序數(shù)據(jù)庫小型項(xiàng)目
UUID / GUID無序日志追蹤
Redis INCR有序Redis電商訂單
Snowflake趨勢有序高并發(fā)系統(tǒng)
Zookeeper 順序 ID有序ZK金融業(yè)務(wù)
百度 UidGenerator有序DB極高高并發(fā)場景
美團(tuán) Leaf有序DB/ZK極高分布式系統(tǒng)

?? 總結(jié):

  • 小型項(xiàng)目:用數(shù)據(jù)庫自增即可。
  • 日志、追蹤:UUID 最方便。
  • 高并發(fā)但輕依賴:Twitter Snowflake / 百度 UidGenerator。
  • 大規(guī)模分布式系統(tǒng):美團(tuán) Leaf 最優(yōu)(生產(chǎn)驗(yàn)證,雙模式保障)。

七、總結(jié)

本文介紹了 雪花算法的原理,并結(jié)合 Spring Boot 實(shí)現(xiàn)了一個(gè) 分布式唯一 ID 生成器。
相比 UUID,雪花算法生成的 ID 更短、更高效,適合作為數(shù)據(jù)庫主鍵。

到此這篇關(guān)于SpringBoot集成雪花算法唯一ID的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)SpringBoot雪花算法唯一ID內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java實(shí)現(xiàn)Rabbitmq延遲隊(duì)列和惰性隊(duì)列

    java實(shí)現(xiàn)Rabbitmq延遲隊(duì)列和惰性隊(duì)列

    本文主要介紹了java實(shí)現(xiàn)Rabbitmq延遲隊(duì)列和惰性隊(duì)列,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-12-12
  • springboot整合mybatis實(shí)現(xiàn)數(shù)據(jù)庫的更新批處理方式

    springboot整合mybatis實(shí)現(xiàn)數(shù)據(jù)庫的更新批處理方式

    這篇文章主要介紹了springboot整合mybatis實(shí)現(xiàn)數(shù)據(jù)庫的更新批處理方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 詳解Java數(shù)據(jù)庫連接JDBC基礎(chǔ)知識(操作數(shù)據(jù)庫:增刪改查)

    詳解Java數(shù)據(jù)庫連接JDBC基礎(chǔ)知識(操作數(shù)據(jù)庫:增刪改查)

    這篇文章主要介紹了詳解Java數(shù)據(jù)庫連接JDBC基礎(chǔ)知識(操作數(shù)據(jù)庫:增刪改查),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • 你可能真沒用過這些 IDEA 插件(建議收藏)

    你可能真沒用過這些 IDEA 插件(建議收藏)

    IDEA 全稱 IntelliJ IDEA,是java編程語言開發(fā)的集成環(huán)境。IntelliJ在業(yè)界被公認(rèn)為最好的java開發(fā)工具。這篇文章主要介紹 IDEA 必用插件的安裝及用法,需要的朋友可以參考下
    2020-08-08
  • Mybatis實(shí)現(xiàn)傳入多個(gè)參數(shù)的四種方法詳細(xì)講解

    Mybatis實(shí)現(xiàn)傳入多個(gè)參數(shù)的四種方法詳細(xì)講解

    這篇文章主要介紹了Mybatis實(shí)現(xiàn)傳入多個(gè)參數(shù)的四種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-01-01
  • springboot3使用redis 最新詳細(xì)方法示例詳解

    springboot3使用redis 最新詳細(xì)方法示例詳解

    本文介紹Spring Boot 3中使用Redis的配置方法與數(shù)據(jù)結(jié)構(gòu)操作,涵蓋String、List、Set、ZSet、Hash、Bitmap等類型的應(yīng)用場景,如緩存、消息隊(duì)列、排行榜等,提供高效數(shù)據(jù)處理方案,感興趣的朋友跟隨小編一起看看吧
    2025-07-07
  • Java中正則表達(dá)式的語法以及matches方法的使用方法

    Java中正則表達(dá)式的語法以及matches方法的使用方法

    正則表達(dá)式(Regular Expression)是一門簡單語言的語法規(guī)范,是強(qiáng)大、便捷、高效的文本處理工具,這篇文章主要給大家介紹了關(guān)于Java中正則表達(dá)式的語法以及matches方法的使用方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-05-05
  • 解決HttpServletResponse和HttpServletRequest取值的2個(gè)坑

    解決HttpServletResponse和HttpServletRequest取值的2個(gè)坑

    這篇文章主要介紹了解決HttpServletResponse和HttpServletRequest取值的2個(gè)坑問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Java字母大小寫轉(zhuǎn)換的方法

    Java字母大小寫轉(zhuǎn)換的方法

    這篇文章主要為大家詳細(xì)介紹了Java字母大小寫轉(zhuǎn)換的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • Spring?Cloud?Gateway集成Sentinel流控詳情

    Spring?Cloud?Gateway集成Sentinel流控詳情

    這篇文章主要介紹了Spring?Cloud?Gateway集成Sentinel流控詳情,Sentinel支持對Spring?Cloud?Gateway、Zuul等主流的API?Gateway進(jìn)行限流,需要的朋友可以參考一下
    2022-09-09

最新評論