GO 实现自增id

本文探讨如何在Go中实现自增ID的功能,包括原子操作的使用和并发安全的考虑,帮助开发者理解如何在高并发环境下确保ID的唯一性和正确递增。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

package guid

import (
	"fmt"
	"github.com/astaxie/beego/orm"
	"sync"
	"time"
)

func init() {
	orm.RegisterModel(new(IdInfo))
}

//模块id信息
type IdInfo struct {
	Id       int    //模块id
	Max      uint64 //最大值
	Interval uint   //区间
}

//id生成器
type IdGenerator struct {
	moduleId      int         //模块id
	curr          uint64      //当前值
	max           uint64      //最大值
	thresholdRate uint8       //阈值百分比(1-100),用于计算threshold
	threshold     uint64      //阈值,curr等于阈值时则开始获取下一区间值
	dbAlia        string      //数据库别名
	nextChan      chan IdInfo //下一区间信息通道
	sync.Mutex
}

func NewIdGenerator(moduleId int, dbAlia string) (*IdGenerator, error) {
	ig := &IdGenerator{
		moduleId:      moduleId,
		dbAlia:        dbAlia,
		thresholdRate: 20,
		nextChan:      make(chan IdInfo, 1),
	}
	err := ig.getNext()
	if err != nil {
		//logger.Error(err)
		return nil, err
	}
	return ig, nil
}

//获取自增id
func (ig *IdGenerator) GenId() uint64 {
	ig.Lock()
	defer ig.Unlock()
	ig.curr++
	if ig.curr > ig.max {
		ig.next()
		ig.curr++
	}

	if ig.curr > ig.max {
		//logger.Error("gen error")
		return 0
	}

	if ig.curr == ig.threshold {
		ig.asyncGetNext()
	}

	return ig.curr

}

//跳到下一区间
func (ig *IdGenerator) next() {
	select {
	case idInfo, ok := <-ig.nextChan:
		if ok {
			ig.curr = idInfo.Max - uint64(idInfo.Interval)
			ig.max = idInfo.Max
			ig.threshold = ig.curr + uint64(ig.thresholdRate)*uint64(idInfo.Interval)/100
		}
	}
}

//异步获取下一区间值
func (ig *IdGenerator) asyncGetNext() {
	go func() {
		retryTimes := time.Duration(1)
		for {
			err := ig.getNext()
			//失败重试
			if err != nil {
				time.Sleep(retryTimes * time.Second)
				retryTimes++
				ig.Lock()
				ig.nextChan = make(chan IdInfo, 1)
				ig.Unlock()
				continue
			}
			break
		}
	}()
}

//获取下一区间值
func (ig *IdGenerator) getNext() (err error) {
	idInfo := &IdInfo{Id: ig.moduleId}
	o := orm.NewOrm()
	o.Using(ig.dbAlia)
	o.Begin()
	defer func() {
		if x := recover(); x != nil {
			//logger.Error(x)
			err = fmt.Errorf("%v", x)
		}
		if err != nil {
			//logger.Error(err)
			o.Rollback()
			close(ig.nextChan)
		} else {
			o.Commit()
			ig.nextChan <- *idInfo
		}
	}()
	err = o.ReadForUpdate(idInfo)
	if err != nil {
		return
	}
	idInfo.Max += uint64(idInfo.Interval)
	_, err = o.Update(idInfo)
	if err != nil {
		return
	}
	return
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值