/* 用于生成唯一的、递增的Id。生成的规则如下: 1、生成的Id包含一个固定前缀值 2、为了生成尽可能多的不重复数字,所以使用int64来表示一个数字,其中: 0 000000000000000 0000000000000000000000000000 00000000000000000000 第一部分:1位,固定为0 第二部分:共TimeBit位,表示当前时间距离基础时间的秒数。范围为[0, math.Pow(2, TimeBit)),以2020-1-1 00:00:00为基准 第三部分:共IdentifierBit位,表示固定唯一标识(机器号或者服务器Id等)。范围为[0, math.Pow(2, IdentifierBit)) 第四部分:共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 TimeIdentifierSeedGenerator struct { timeBit int32 // 时间戳所占的位数 timeBitOffset int32 // 时间戳的偏移位数 startTimeStamp int64 // 起始时间戳 endTimeStamp int64 // 结束时间戳 identifier int64 // 唯一标识 identifierBit int32 // 唯一标识(机器号或者服务器Id等)所占的位数 identifierBitOffset int32 // 唯一标识的偏移位数 seedBit int32 // 自增种子所占的位数 seedBitOffset int32 // 自增种子的偏移位数 minSeed int64 // 最小的种子值 maxSeed int64 // 最大的种子值 currSeed int64 // 当前种子值 mutex sync.Mutex // 锁对象 } func (this *TimeIdentifierSeedGenerator) 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 *TimeIdentifierSeedGenerator) 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 *TimeIdentifierSeedGenerator) GenerateNewId() (int64, error) { timestamp, err := this.getTimeStamp() if err != nil { return 0, err } seed := this.getNewSeed() id := (timestamp << this.timeBitOffset) | (this.identifier << this.identifierBitOffset) | (seed << this.seedBitOffset) return id, nil } // 创建新的Id生成器对象(为了保证Id的唯一,需要保证生成的对象全局唯一) // timeBit + identifierBit + seedBit <= 63 // timeBit:时间的位数 // identifier:id唯一标识 // identifierBit:id唯一标识(机器号或者服务器Id等)的位数 // seedBit:自增种子的位数 // 返回值: // 新的Id生成器对象 // 错误对象 func NewTimeIdentifierSeedGenerator(timeBit int32, identifier int64, identifierBit, seedBit int32) (*TimeIdentifierSeedGenerator, error) { // 之所以使用63位而不是64,是为了保证值为正数 if timeBit+identifierBit+seedBit > 63 { return nil, fmt.Errorf("总位数%d超过63位,请调整所有值的合理范围。", timeBit+identifierBit+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 := &TimeIdentifierSeedGenerator{ timeBit: timeBit, startTimeStamp: startTimeStamp, endTimeStamp: startTimeStamp + int64(math.Pow(2, float64(timeBit))) - 1, identifier: identifier, identifierBit: identifierBit, seedBit: seedBit, minSeed: 0, maxSeed: int64(math.Pow(2, float64(seedBit))) - 1, currSeed: 0, } obj.seedBitOffset = 0 obj.identifierBitOffset = obj.seedBitOffset + obj.seedBit obj.timeBitOffset = obj.identifierBitOffset + obj.identifierBit return obj, nil }