Trình tạo ULID
Tạo ID duy nhất có thể sắp xếp theo thứ tự từ điển
Nhấn Tạo để tạo ULID
ULID là gì?
ULID (Universally Unique Lexicographically Sortable Identifier) là định dạng định danh 128-bit được thiết kế để vừa duy nhất vừa có thể sắp xếp một cách tự nhiên.
ULID được mã hóa sử dụng bảng chữ cái Crockford's Base32, tạo ra chuỗi 26 ký tự nhỏ gọn, URL-safe, không phân biệt chữ hoa chữ thường và không có các ký tự mơ hồ về mặt hình ảnh.
Thông số kỹ thuật ULID được tạo bởi Alizain Feerasta và được sử dụng rộng rãi trong các hệ thống phân tán, event sourcing và khóa chính database.
Cấu trúc ULID
ULID rộng 128 bit, được chia thành hai thành phần:
| Timestamp | Ngẫu nhiên |
|---|---|
| 01ARZ3NDEK | TSVE4RRFFQ69G5FAV |
| 48 bit — Timestamp Unix tính bằng mili giây. Mã hóa thời gian tạo với độ chính xác 1ms. Bao gồm các ngày đến năm 10889. | 80 bit — dữ liệu ngẫu nhiên an toàn về mặt mật mã. Được tái tạo mới cho mỗi ULID (trừ khi sử dụng chế độ đơn điệu). |
Được mã hóa dưới dạng 26 ký tự Crockford Base32: 10 ký tự đầu tiên đại diện cho timestamp, 16 ký tự cuối đại diện cho thành phần ngẫu nhiên.
Bảng chữ cái Crockford Base32
ULID sử dụng mã hóa Crockford's Base32, sử dụng 32 trong 36 ký tự chữ số. Bảng chữ cái là: 0123456789ABCDEFGHJKMNPQRSTVWXYZ
Bốn ký tự bị loại trừ có chủ ý:
IvàLbị loại trừ — dễ nhầm lẫn với chữ số1Obị loại trừ — dễ nhầm lẫn với chữ số0Ubị loại trừ — tránh các từ thô tục vô tình trong ID được tạo- Mã hóa
không phân biệt chữ hoa chữ thường—01ARZ3NDEKTSV4RRFFQ69G5FAVvà01arz3ndektsv4rrffq69g5favlà cùng ULID
Crockford Base32 hiệu quả hơn hệ thập lục phân (32 ký hiệu so với 16) và dễ đọc hơn Base64 cho con người.
ULID so với UUID
ULID và UUID đều đại diện cho các định danh 128-bit, nhưng khác nhau đáng kể về mã hóa và mục tiêu thiết kế:
| Thuộc tính | ULID | UUID |
|---|---|---|
| Định dạng | Crockford Base32 | Hex có gạch nối |
| Độ dài | 26 ký tự | 36 ký tự |
| Timestamp | Unix ms 48-bit | Không có (v4) hoặc ms 48-bit (v7) |
| Có thể Sắp xếp | Có — theo thứ tự từ điển | Không (v4) / Có (v7) |
| URL-safe | Có (chỉ chữ số) | Có (với dấu gạch nối) |
| Phụ thuộc | Yêu cầu thư viện | Gốc (crypto.randomUUID) |
| Hỗ trợ DB | Lưu dưới dạng CHAR(26) hoặc BINARY(16) | Kiểu cột UUID gốc |
| Thông số kỹ thuật | Thông số kỹ thuật cộng đồng (ulid.github.io) | RFC 4122 / RFC 9562 |
Nếu bạn đã trong hệ sinh thái UUID (các cột uuid PostgreSQL, REST API), UUID v7 thường phù hợp hơn ULID. Nếu bạn thích mã hóa thân thiện với con người hơn, ULID là lựa chọn xuất sắc.
ULID so với nanoid
Cả ULID và nanoid đều tạo ra các định danh ngắn, URL-safe, nhưng có các mục tiêu thiết kế khác nhau:
| Thuộc tính | ULID | NanoID |
|---|---|---|
| Timestamp | Có — Unix ms 48-bit | Không |
| Có thể Sắp xếp | Có | Không |
| Độ dài mặc định | 26 ký tự | 21 ký tự |
| Entropy | 80 bit (thành phần ngẫu nhiên) | ~126 bit |
| Bảng chữ cái | Crockford Base32 (32 ký tự) | URL-safe Base64 (64 ký tự) |
| Độ dài có thể tùy chỉnh | Không | Có (độ dài bất kỳ) |
| Trường hợp sử dụng | ID theo thứ tự thời gian, khóa chính DB | Token ngẫu nhiên, URL ngắn, khóa API |
Chọn ULID khi bạn cần sắp xếp theo thời gian. Chọn nanoid khi bạn muốn entropy tối đa trong chuỗi ngắn, ngẫu nhiên.
Sử dụng ULID trong Database
ULID có thể được lưu trong database theo nhiều cách tùy thuộc vào yêu cầu của bạn:
Ví dụ Mã
Tạo ULID yêu cầu thư viện ulid (có sẵn cho JavaScript, Python, Go, Rust, và nhiều hơn nữa):
// Using the 'ulid' npm package
import { ulid } from 'ulid'
const id = ulid() // "01ARZ3NDEKTSV4RRFFQ69G5FAV"
const id2 = ulid() // "01ARZ3NDEKXXXXXXXXXXXX..." (same ms, incremented random)
// With a custom timestamp
const id3 = ulid(1469918176385) // deterministic time portion
// Extract the timestamp back out
import { decodeTime } from 'ulid'
decodeTime(id) // → 1469918176385 (Unix ms)# Using python-ulid
from ulid import ULID
uid = ULID()
str(uid) # "01ARZ3NDEKTSV4RRFFQ69G5FAV"
uid.timestamp # 1469918176.385
uid.datetime # datetime(2016, 7, 30, 23, 36, 16, 385000, tzinfo=timezone.utc)
# Parse an existing ULID string
parsed = ULID.from_str("01ARZ3NDEKTSV4RRFFQ69G5FAV")
parsed.timestamp # 1469918176.385-- Store ULIDs as TEXT or CHAR(26)
CREATE TABLE events (
id CHAR(26) PRIMARY KEY DEFAULT gen_ulid(), -- if using a PG extension
name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Or pass the ULID from your application layer
INSERT INTO events (id, name, created_at)
VALUES ('01ARZ3NDEKTSV4RRFFQ69G5FAV', 'user.signup', NOW());
-- Range queries are efficient because ULIDs sort chronologically
SELECT * FROM events
WHERE id > '01ARZ3NDEKTSV4RRFFQ69G5FAV'
ORDER BY id
LIMIT 20;// Pure browser / Deno / Node.js implementation (no dependencies)
const CROCKFORD = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'
function encodeTime(ms) {
let result = '', n = BigInt(ms)
for (let i = 9; i >= 0; i--) {
result = CROCKFORD[Number(n & 31n)] + result
n >>= 5n
}
return result
}
function encodeRandom(bytes) {
let n = 0n
for (const b of bytes) n = (n << 8n) | BigInt(b)
let result = ''
for (let i = 15; i >= 0; i--) {
result = CROCKFORD[Number(n & 31n)] + result
n >>= 5n
}
return result
}
function generateULID() {
const randomBytes = new Uint8Array(10)
crypto.getRandomValues(randomBytes)
return encodeTime(Date.now()) + encodeRandom(randomBytes)
}