本文提供 Java 生成 UUID 的兩種標準方式(隨機 UUID、基於名字的 UUID),以及一種基於時間戳的長整型 ID 生成器,適用於分佈式系統主鍵、訂單號、追蹤 ID 等場景。
| 類型 | 方法 | 特點 | 適用場景 |
|---|---|---|---|
| 隨機 UUID (v4) | UUID.randomUUID() | 122 位隨機,極低衝突概率,無序 | 通用唯一標識、分佈式主鍵 |
| 基於名字 UUID (v3/v5) | UUID.nameUUIDFromBytes() | 確定性:同輸入必同輸出,MD5/SHA-1 | 同名實體去重、內容寻址 |
| 時間 UUID (v1/v2) | 需第三方庫 | 含時間戳+MAC,有序,洩露 MAC 風險 | 需時間排序的場景 |
import java.util.Date;
import java.util.UUID;
public class IdGenerator {
/**
* 生成標準隨機 UUID (版本 4)
* @return 32 位十六進制字符串(無連字符)
*/
public static synchronized String generateUuid() {
UUID uuid = UUID.randomUUID();
return uuid.toString().replace("-", "");
}
/**
* 基於名字生成確定性 UUID (版本 3,MD5)
* @param name 輸入名字(如用戶 ID、URL、內容哈希)
* @return 32 位十六進制字符串
*/
public static synchronized String generateUuid(String name) {
UUID uuid = UUID.nameUUIDFromBytes(name.getBytes(StandardCharsets.UTF_8));
return uuid.toString().replace("-", "");
}
/**
* 基於時間戳生成長整型 ID
* 格式:yyyyMMddHHmmssSSS + 2位序列號 (共 17+2=19 位)
* 同一毫秒內最多生成 99 個不重複 ID
* @return 19 位長整型 ID
*/
public static synchronized long generateLongId() {
// 1. 獲取精確到毫秒的時間戳字符串
String timestamp = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
// 2. 靜態序列號(類級別,同一毫秒內遞增)
// 注意:分佈式環境下需引入機器 ID 或使用 Snowflake 算法
if (sequence >= 99) sequence = 0;
sequence++;
// 3. 拼接序列號(補零)
String seqStr = (sequence < 10) ? "0" + sequence : String.valueOf(sequence);
return Long.parseLong(timestamp + seqStr);
}
// 靜態序列號計數器
private static int sequence = 0;
// 測試主方法
public static void main(String[] args) {
System.out.println("隨機 UUID: " + generateUuid());
System.out.println("名字 UUID: " + generateUuid("user:1001"));
System.out.println("時間長 ID: " + generateLongId());
System.out.println("時間長 ID: " + generateLongId());
}
}
上述 generateLongId() 僅適用於單機或單寫入節點。分佈式系統需引入機器標識。
/**
* Snowflake ID 生成器 (64 位 long)
* 1bit 符號位 | 41bit 時間戳(毫秒) | 10bit 機器ID | 12bit 序列號
* 支援 1024 個節點,每節點每毫秒 4096 個 ID
*/
public class SnowflakeIdGenerator {
private final long workerId;
private final long datacenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
// 時間起始點 (2020-01-01)
private static final long EPOCH = 1577836800000L;
private static final long WORKER_ID_BITS = 5L;
private static final long DATACENTER_ID_BITS = 5L;
private static final long SEQUENCE_BITS = 12L;
private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS);
private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);
private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
public SnowflakeIdGenerator(long workerId, long datacenterId) {
if (workerId > MAX_WORKER_ID || workerId < 0)
throw new IllegalArgumentException("Worker ID 超出範圍");
if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0)
throw new IllegalArgumentException("Datacenter ID 超出範圍");
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException("時鐘回撥,拒絕生成 ID");
}
if (timestamp == lastTimestamp) {
sequence = (sequence + 1) & SEQUENCE_MASK;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - EPOCH) << TIMESTAMP_SHIFT)
| (datacenterId << DATACENTER_ID_SHIFT)
| (workerId << WORKER_ID_SHIFT)
| sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) timestamp = timeGen();
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
}
-- 表結構
CREATE TABLE id_segment (
biz_tag VARCHAR(128) PRIMARY KEY,
max_id BIGINT NOT NULL,
step INT NOT NULL DEFAULT 1000,
version INT NOT NULL DEFAULT 0
);
-- 獲取 ID 段 (樂觀鎖)
UPDATE id_segment
SET max_id = max_id + step, version = version + 1
WHERE biz_tag = 'ORDER' AND version = #{version};
-- 應用端緩存當前段,用完再取下一段
| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 單機/微服務少量節點 | 時間戳+序列號 / UUID | 簡單、無依賴 |
| 高併發分佈式系統 | Snowflake / UidGenerator | 高性能、有序、去中心化 |
| 嚴格遞增、可審計 | 資料庫號段模式 | 強一致、易監控 |
| 業務語義化 ID | 前綴 + 時間 + 序列 (如 ORD202401150001) | 可讀性強 |
| 內容去重/寻址 | 基於名字 UUID (v3/v5) | 確定性 |
UUID.randomUUID() 是最通用的選擇,無狀態、無協調