122 lines
4.2 KiB
Go
122 lines
4.2 KiB
Go
/*
|
||
用于生成唯一的、递增的Id。生成的规则如下:
|
||
1、生成的Id包含一个固定前缀值
|
||
2、为了生成尽可能多的不重复数字,所以使用int64来表示一个数字,其中:
|
||
0 000000000000000 0000000000000000000000000000 00000000000000000000
|
||
第一部分:1位,固定为0
|
||
第二部分:共IdentifierBit位,表示固定唯一标识(机器号或者服务器Id等)。范围为[0, math.Pow(2, IdentifierBit))
|
||
第三部分:共TimeBit位,表示当前时间距离基础时间的秒数。范围为[0, math.Pow(2, TimeBit)),以2020-1-1 00:00:00为基准
|
||
第四部分:共SeedBit位,表示自增种子。范围为[0, math.Pow(2, SeedBit))
|
||
3、总体而言,此规则支持每秒生成math.Pow(2, SeedBit)个不同的数字,并且在math.Pow(2, TimeBit)/60/60/24/365年的时间范围内有效
|
||
*/
|
||
|
||
/*
|
||
修改记录:
|
||
2020-03-04 14:30:00 调整了时间和唯一标识在Id中的位置,以便生成递增的Id
|
||
2020-04-20 21:10:00 同步了C#版本的逻辑
|
||
*/
|
||
|
||
package idUtil
|
||
|
||
import (
|
||
"fmt"
|
||
"math"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
type IdentifierTimeSeedGenerator struct {
|
||
identifier int64 // 唯一标识
|
||
identifierBit int32 // 唯一标识(机器号或者服务器Id等)所占的位数
|
||
identifierBitOffset int32 // 唯一标识的偏移位数
|
||
|
||
timeBit int32 // 时间戳所占的位数
|
||
timeBitOffset int32 // 时间戳的偏移位数
|
||
startTimeStamp int64 // 起始时间戳
|
||
endTimeStamp int64 // 结束时间戳
|
||
|
||
seedBit int32 // 自增种子所占的位数
|
||
seedBitOffset int32 // 自增种子的偏移位数
|
||
minSeed int64 // 最小的种子值
|
||
maxSeed int64 // 最大的种子值
|
||
currSeed int64 // 当前种子值
|
||
|
||
mutex sync.Mutex // 锁对象
|
||
}
|
||
|
||
func (this *IdentifierTimeSeedGenerator) getTimeStamp() (int64, error) {
|
||
if time.Now().Unix() > this.endTimeStamp {
|
||
return 0, fmt.Errorf("Time's value is out of scope")
|
||
}
|
||
|
||
return time.Now().Unix() - this.startTimeStamp, nil
|
||
}
|
||
|
||
func (this *IdentifierTimeSeedGenerator) getNewSeed() int64 {
|
||
this.mutex.Lock()
|
||
defer this.mutex.Unlock()
|
||
|
||
if this.currSeed >= this.maxSeed {
|
||
this.currSeed = this.minSeed
|
||
} else {
|
||
this.currSeed = this.currSeed + 1
|
||
}
|
||
|
||
return this.currSeed
|
||
}
|
||
|
||
// 生成新的Id
|
||
// identifier:Id的唯一标识值。取值范围必须可以用创建对象时指定的唯一标识值的位数来表示,否则会返回参数超出范围的错误
|
||
// 返回值:
|
||
// 新的Id
|
||
// 错误对象
|
||
func (this *IdentifierTimeSeedGenerator) GenerateNewId() (int64, error) {
|
||
timestamp, err := this.getTimeStamp()
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
seed := this.getNewSeed()
|
||
id := (this.identifier << this.identifierBitOffset) | (timestamp << this.timeBitOffset) | (seed << this.seedBitOffset)
|
||
|
||
return id, nil
|
||
}
|
||
|
||
// 创建新的Id生成器对象(为了保证Id的唯一,需要保证生成的对象全局唯一)
|
||
// identifierBit + timeBit + seedBit <= 63
|
||
// identifier:id唯一标识
|
||
// identifierBit:id唯一标识(机器号或者服务器Id等)的位数
|
||
// timeBit:时间的位数
|
||
// seedBit:自增种子的位数
|
||
// 返回值:
|
||
// 新的Id生成器对象
|
||
// 错误对象
|
||
func NewIdentifierTimeSeedGenerator(identifier int64, identifierBit, timeBit, seedBit int32) (*IdentifierTimeSeedGenerator, error) {
|
||
// 之所以使用63位而不是64,是为了保证值为正数
|
||
if identifierBit+timeBit+seedBit > 63 {
|
||
return nil, fmt.Errorf("总位数%d超过63位,请调整所有值的合理范围。", identifierBit+timeBit+seedBit)
|
||
}
|
||
|
||
if identifier < 0 || identifier > int64(math.Pow(2, float64(identifierBit)))-1 {
|
||
return nil, fmt.Errorf("唯一标识值溢出,有效范围为【0,%d】", int64(math.Pow(2, float64(identifierBit)))-1)
|
||
}
|
||
|
||
startTimeStamp := time.Date(2019, time.January, 1, 0, 0, 0, 0, time.Local).Unix()
|
||
obj := &IdentifierTimeSeedGenerator{
|
||
identifier: identifier,
|
||
identifierBit: identifierBit,
|
||
timeBit: timeBit,
|
||
startTimeStamp: startTimeStamp,
|
||
endTimeStamp: startTimeStamp + int64(math.Pow(2, float64(timeBit))) - 1,
|
||
seedBit: seedBit,
|
||
minSeed: 0,
|
||
maxSeed: int64(math.Pow(2, float64(seedBit))) - 1,
|
||
currSeed: 0,
|
||
}
|
||
|
||
obj.seedBitOffset = 0
|
||
obj.timeBitOffset = obj.seedBitOffset + obj.seedBit
|
||
obj.identifierBitOffset = obj.timeBitOffset + obj.timeBit
|
||
|
||
return obj, nil
|
||
}
|