用golang 生成顺序UUID的方法
UUID(Universally Unique Identifier)是一种128位的全局唯一标识符。它通常用于标识信息,不依赖中央协调机构,因此在分布式系统中特别有用。生成连续的UUID并不是UUID设计的目标,因为UUID的主要目的是确保唯一性,而不是顺序性。然而,可以通过某些方法生成具有一定顺序性的UUID。
以下是一个基于时间戳和自增计数器的顺序UUID生成器的实现:
package main
import (
"encoding/binary"
"fmt"
"sync"
"time"
"github.com/google/uuid"
)
type SequentialUUIDGenerator struct {
mu sync.Mutex
lastTimestamp int64
counter uint64
}
func NewSequentialUUIDGenerator() *SequentialUUIDGenerator {
return &SequentialUUIDGenerator{}
}
func (gen *SequentialUUIDGenerator) Generate() uuid.UUID {
gen.mu.Lock()
defer gen.mu.Unlock()
currentTimestamp := time.Now().UnixNano() / int64(time.Millisecond)
if currentTimestamp != gen.lastTimestamp {
gen.lastTimestamp = currentTimestamp
gen.counter = 0
} else {
gen.counter++
}
// 将时间戳和计数器合并为UUID
var uuidBytes [16]byte
binary.BigEndian.PutUint64(uuidBytes[:8], uint64(currentTimestamp))
binary.BigEndian.PutUint64(uuidBytes[8:], gen.counter)
newUUID, err := uuid.FromBytes(uuidBytes[:])
if err != nil {
panic(err)
}
return newUUID
}
func main() {
generator := NewSequentialUUIDGenerator()
for i := 0; i < 10; i++ {
fmt.Println(generator.Generate())
}
}
解释
- 结构体与初始化:
SequentialUUIDGenerator
结构体包含了一个互斥锁(sync.Mutex
),一个记录上一次生成UUID时的时间戳(lastTimestamp
),以及一个计数器(counter
)。NewSequentialUUIDGenerator
函数用于初始化生成器。
- 生成UUID方法:
Generate
方法获取当前时间戳(以毫秒为单位),并与上次的时间戳进行比较。- 如果当前时间戳与上次不相同,则重置计数器;否则计数器递增。
- 将时间戳和计数器合并为一个16字节的数组,并转换为UUID。
- 主函数:
- 在
main
函数中,创建一个生成器实例并生成10个UUID进行打印。
- 在
使用互斥锁
为了确保生成UUID时的线程安全,使用了互斥锁(sync.Mutex
)来保护对lastTimestamp
和counter
的访问。
注意事项
- 生成的UUID不是标准的UUID格式,但在一定程度上能满足顺序性的需求。
- 使用了
github.com/google/uuid
包来处理UUID相关操作。如果没有该包,可以通过go get github.com/google/uuid
来安装。
通过这种方式,您可以在Go语言中生成具有顺序性的UUID。
上面的代码生成的UUID是一个标准的UUID格式,它是一个包含数字和字母的字符串。例如,生成的UUID可能看起来像这样:
6b8b4567-88b5-42c5-91e6-6f573d93c9f4
如果您希望生成一个纯数字的顺序UUID,可以调整代码以生成只包含数字的字符串。以下是一个示例:
package main
import (
"fmt"
"sync"
"time"
)
type SequentialUUIDGenerator struct {
mu sync.Mutex
lastTimestamp int64
counter uint64
}
func NewSequentialUUIDGenerator() *SequentialUUIDGenerator {
return &SequentialUUIDGenerator{}
}
func (gen *SequentialUUIDGenerator) Generate() string {
gen.mu.Lock()
defer gen.mu.Unlock()
currentTimestamp := time.Now().UnixNano() / int64(time.Millisecond)
if currentTimestamp != gen.lastTimestamp {
gen.lastTimestamp = currentTimestamp
gen.counter = 0
} else {
gen.counter++
}
// 将时间戳和计数器合并为一个字符串
// 时间戳的长度为13位,计数器的长度可以根据需要调整
return fmt.Sprintf("%013d%05d", currentTimestamp, gen.counter)
}
func main() {
generator := NewSequentialUUIDGenerator()
for i := 0; i < 10; i++ {
fmt.Println(generator.Generate())
}
}
生成的结果
生成的结果将是一个包含纯数字的字符串,例如:
162378907100000
162378907100001
162378907100002
如果需要生成较短的纯数字顺序UUID,可以通过缩短时间戳的位数以及控制计数器的位数。以下是一个示例,使用当前时间戳(秒级)并结合一个较短的计数器来生成较短的纯数字顺序UUID:
package main
import (
"fmt"
"sync"
"time"
)
type SequentialUUIDGenerator struct {
mu sync.Mutex
lastTimestamp int64
counter int
}
func NewSequentialUUIDGenerator() *SequentialUUIDGenerator {
return &SequentialUUIDGenerator{}
}
func (gen *SequentialUUIDGenerator) Generate() string {
gen.mu.Lock()
defer gen.mu.Unlock()
// 获取当前时间戳的秒部分,并只取后5位
currentTimestamp := time.Now().Unix() % 100000
if currentTimestamp != gen.lastTimestamp {
gen.lastTimestamp = currentTimestamp
gen.counter = 0
} else {
gen.counter++
}
// 将时间戳和计数器合并为一个字符串,控制其总长度在10位以内
return fmt.Sprintf("%05d%04d", currentTimestamp, gen.counter)
}
func main() {
generator := NewSequentialUUIDGenerator()
for i := 0; i < 10; i++ {
fmt.Println(generator.Generate())
}
}
解释
- 结构体与初始化:
SequentialUUIDGenerator
结构体包含一个互斥锁(sync.Mutex
),一个记录上一次生成UUID时的时间戳(lastTimestamp
),以及一个计数器(counter
)。NewSequentialUUIDGenerator
函数用于初始化生成器。
- 生成UUID方法:
Generate
方法获取当前时间戳的秒部分,并只取后5位。- 如果当前时间戳的秒部分与上次不同,则重置计数器;否则计数器递增。
- 将时间戳和计数器合并为一个字符串,控制其总长度在10位以内。
- 主函数:
- 在
main
函数中,创建一个生成器实例并生成10个UUID进行打印。
- 在
生成的结果
生成的结果将是一个较短的纯数字字符串,例如:
123450000
123450001
123450002
...