返回
ULID:一种高效简洁的唯一标识符
后端
2024-02-04 09:34:56
导言
在现代软件系统中,生成唯一标识符(ID)至关重要。这些 ID 可用于跟踪用户、订单或任何其他需要唯一标识的实体。传统上,UUID(通用唯一标识符)是生成 ID 的流行选择,但它存在一些缺点,例如存储空间大、生成速度慢。
ULID(Universally Unique Lexicographically Sortable Identifier,通用唯一可按字典顺序排序的标识符)是一种较新的 ID 格式,旨在解决 UUID 的这些缺点。它不仅占用更少的存储空间,而且生成速度也更快,同时还保留了 UUID 的唯一性和排序特性。
ULID 规范
ULID 由以下部分组成:
- 时间戳 (48 位) :以毫秒为单位表示自纪元(1970 年 1 月 1 日午夜)以来的时间。
- 随机性 (80 位) :由伪随机数生成器 (PRNG) 生成的随机比特串。
ULID 的总长度为 128 位,通常表示为 26 个字符的字符串。字符集由大写字母 (A-Z)、小写字母 (a-z)、数字 (0-9) 和连字符 (-) 组成。
ULID 实现
我们可以基于 Java 语言实现 ULID。首先,我们需要一个伪随机数生成器 (PRNG)。Java 提供了 SecureRandom
类,我们可以使用它来生成安全的随机比特串。
接下来,我们需要将时间戳和随机性编码为字符串。我们可以使用 Base32
编码,它将 5 个二进制位编码为 8 个字符。
import java.security.SecureRandom;
import java.time.Instant;
public class Ulid {
private static final SecureRandom RANDOM = new SecureRandom();
private static final String BASE32_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
public static String generate() {
// 获取当前时间戳
long timestamp = Instant.now().toEpochMilli();
// 生成随机性
byte[] randomness = new byte[10];
RANDOM.nextBytes(randomness);
// 将时间戳编码为 Base32
String timestampString = Base32.encode(timestamp);
// 将随机性编码为 Base32
String randomnessString = Base32.encode(randomness);
// 返回 ULID 字符串
return timestampString + randomnessString;
}
private static class Base32 {
private static final char[] ALPHABET = BASE32_ALPHABET.toCharArray();
public static String encode(long value) {
StringBuilder sb = new StringBuilder();
while (value > 0) {
sb.append(ALPHABET[(int) (value % 32)]);
value /= 32;
}
return sb.reverse().toString();
}
}
}
优势
ULID 具有以下优势:
- 存储空间小: ULID 仅需 26 个字符,而 UUID 需要 36 个字符。
- 生成速度快: ULID 的生成速度比 UUID 快,因为它不需要调用外部服务或复杂的算法。
- 唯一性: 由于包含了时间戳和随机性,ULID 可以确保生成唯一 ID。
- 可排序: ULID 按照时间顺序排序,这对于需要按时间检索或处理数据的应用程序非常有用。
应用场景
ULID 可用于各种应用场景,包括:
- 数据库主键
- 订单编号
- 用户会话 ID
- 日志跟踪
总结
ULID 是一种高效简洁的唯一标识符格式。它具有存储空间小、生成速度快、唯一性和可排序性的特点。通过 Java 语言的实现,我们可以深入了解 ULID 的底层原理,并将其应用于我们的项目中。