golang实现通用唯一词典排序标识符ULID的插件库ulid的使用
Golang实现通用唯一词典排序标识符ULID的插件库ulid的使用
ULID(Universally Unique Lexicographically Sortable Identifier)是一种通用唯一词典排序标识符,相比UUID有以下优势:
ULID的优势
- 兼容UUID/GUID
- 每毫秒可生成1.21e+24个唯一ULID
- 可词典排序
- 使用26个字符编码(UUID为36个)
- 使用Crockford的base32编码,效率更高且更易读
- 大小写不敏感
- 无特殊字符(URL安全)
- 单调排序顺序(正确处理同一毫秒内的生成)
安装
使用Go模块安装:
go get github.com/oklog/ulid/v2
基本使用
简单生成ULID
package main
import (
"fmt"
"github.com/oklog/ulid/v2"
)
func main() {
// 最简单的方式生成ULID
fmt.Println(ulid.Make())
// 输出示例: 01G65Z755AFWAKHE12NY0CQ9FH
}
高级用法
package main
import (
"fmt"
"math/rand"
"time"
"github.com/oklog/ulid/v2"
)
func main() {
// 使用自定义熵源
entropy := rand.New(rand.NewSource(time.Now().UnixNano()))
// 获取当前时间的毫秒时间戳
ms := ulid.Timestamp(time.Now())
// 生成ULID
id := ulid.New(ms, entropy)
fmt.Println(id)
// 输出示例: 01G65Z755AFWAKHE12NY0CQ9FH
}
安全考虑
- 对于安全敏感的场景,应使用
crypto/rand
作为熵源 - 对于高性能场景,可以考虑使用
sync.Pool
来池化熵源
命令行工具
该库还提供了命令行工具:
go install github.com/oklog/ulid/v2/cmd/ulid@latest
使用示例:
$ ulid
01D78XYFJ1PRM1WPBCBT3VHMNV
$ ulid -z
01D78XZ44G0000000000000000
$ ulid 01D78XZ44G0000000000000000
Sun Mar 31 03:51:23.536 UTC 2019
ULID规范
组成部分
- 时间戳:48位,UNIX毫秒时间戳
- 熵:80位,用户定义的熵源
编码
使用Crockford的Base32编码,排除了容易混淆的字母I、L、O和U:
0123456789ABCDEFGHJKMNPQRSTVWXYZ
字符串表示
01AN4Z07BY 79KA1307SR9X4MV3
|----------| |----------------|
Timestamp Entropy
10 chars 16 chars
48bits 80bits
base32 base32
性能基准
在Intel Core i7 Ivy Bridge 2.7 GHz,MacOS 10.12.1和Go 1.8.0beta1上的基准测试结果:
BenchmarkNew/WithCryptoEntropy-8 2000000 771 ns/op
BenchmarkNew/WithEntropy-8 20000000 65.8 ns/op
BenchmarkNew/WithoutEntropy-8 50000000 30.0 ns/op
BenchmarkParse-8 50000000 30.0 ns/op
BenchmarkString-8 20000000 64.9 ns/op
以上是Golang中使用ulid库生成和处理ULID标识符的基本方法。ULID提供了比UUID更好的排序性能和更紧凑的表示形式,适合需要按时间排序的场景。
更多关于golang实现通用唯一词典排序标识符ULID的插件库ulid的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现通用唯一词典排序标识符ULID的插件库ulid的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 实现 ULID 的插件库使用指南
ULID (Universally Unique Lexicographically Sortable Identifier) 是一种比 UUID 更适合数据库主键的标识符方案,它同时具备:
- 按时间排序的特性
- 128位的唯一性保证
- 比 UUID 更友好的字符串表示形式
安装 ULID 库
go get github.com/oklog/ulid/v2
基本使用示例
package main
import (
"fmt"
"math/rand"
"time"
"github.com/oklog/ulid/v2"
)
func main() {
// 1. 生成新的 ULID
entropy := rand.New(rand.NewSource(time.Now().UnixNano()))
ms := ulid.Timestamp(time.Now())
id, err := ulid.New(ms, entropy)
if err != nil {
panic(err)
}
fmt.Println("Generated ULID:", id)
// 2. 解析字符串为 ULID
parsed, err := ulid.Parse(id.String())
if err != nil {
panic(err)
}
fmt.Println("Parsed ULID:", parsed)
// 3. 获取时间部分
fmt.Println("Time:", ulid.Time(id.Time()))
// 4. 比较两个 ULID
id2, _ := ulid.New(ulid.Timestamp(time.Now().Add(time.Second)), entropy)
fmt.Println("Comparison:", id.Compare(id2))
}
高级用法
自定义熵源
func customEntropy() {
// 使用 crypto/rand 作为更安全的熵源
entropy := ulid.Monotonic(rand.New(rand.NewSource(time.Now().UnixNano())), 0)
id := ulid.MustNew(ulid.Timestamp(time.Now()), entropy)
fmt.Println("Secure ULID:", id)
}
批量生成 ULID
func batchGenerate() {
entropy := rand.New(rand.NewSource(time.Now().UnixNano()))
now := time.Now()
ids := make([]ulid.ULID, 5)
for i := range ids {
ids[i] = ulid.MustNew(ulid.Timestamp(now.Add(time.Duration(i)*time.Millisecond), entropy)
}
for _, id := range ids {
fmt.Println(id)
}
}
数据库集成示例
type User struct {
ID ulid.ULID `json:"id" db:"id"`
Name string `json:"name" db:"name"`
}
func createUser(name string) User {
entropy := ulid.Monotonic(rand.New(rand.NewSource(time.Now().UnixNano())), 0)
return User{
ID: ulid.MustNew(ulid.Timestamp(time.Now()), entropy),
Name: name,
}
}
func dbExample() {
user := createUser("Alice")
fmt.Printf("User created: %+v\n", user)
// 模拟数据库存储和查询
db := make(map[string]User)
db[user.ID.String()] = user
// 查询
if u, ok := db[user.ID.String()]; ok {
fmt.Println("Found user:", u.Name)
}
}
性能考虑
- ULID 生成速度比 UUID v4 稍慢,但比 UUID v1/v2 快
- 对于高并发场景,建议使用
ulid.Monotonic
熵源 - 字符串表示形式比 UUID 更紧凑(26个字符 vs 36个字符)
适用场景
- 数据库主键(特别是需要按时间排序的)
- 分布式系统唯一标识
- 日志追踪ID
- 需要人类可读但又保持唯一性的标识符
ULID 提供了比传统 UUID 更好的排序特性,同时保持了足够的唯一性,非常适合作为现代分布式系统的标识符方案。