From 5220cfff6d68f24875c5ce832bbe4541b9fe6639 Mon Sep 17 00:00:00 2001 From: zhangqian <zhangqian@123.com> Date: 星期五, 08 十二月 2023 10:26:38 +0800 Subject: [PATCH] 使用雪花算法生成表id,解决数据同步表相同记录id不一致问题 --- model/dashboard.go | 2 model/model.go | 24 ++++++ service/report_work.go | 3 go.sum | 2 model/procedures.go | 2 go.mod | 1 pkg/snowflake/snowflake.go | 148 +++++++++++------------------------- 7 files changed, 77 insertions(+), 105 deletions(-) diff --git a/go.mod b/go.mod index 68bc670..fca578c 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ github.com/IBM/netaddr v1.5.0 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/ajg/form v1.5.1 // indirect + github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect diff --git a/go.sum b/go.sum index dc9da1f..c5660cd 100644 --- a/go.sum +++ b/go.sum @@ -64,6 +64,8 @@ github.com/apache/plc4x/plc4go v0.0.0-20230817065839-dd203446b558/go.mod h1:KC3Kj7xv0dlGb5yT1+Mz9cI9YZj1RD19cr8TyqfnBDU= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= diff --git a/model/dashboard.go b/model/dashboard.go index bd6bdf8..436e2db 100644 --- a/model/dashboard.go +++ b/model/dashboard.go @@ -9,7 +9,7 @@ type ( Dashboard struct { - gorm.Model + CommonModel Version string DeviceRunningAmount int //寮�鏈哄彴鏁� TotalProductionAmount int //鎬讳骇閲� diff --git a/model/model.go b/model/model.go new file mode 100644 index 0000000..f7b56b7 --- /dev/null +++ b/model/model.go @@ -0,0 +1,24 @@ +package model + +import ( + "apsClient/pkg/snowflake" + "github.com/jinzhu/gorm" + "time" +) + +type CommonModel struct { + ID uint `gorm:"primary_key"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time `sql:"index"` +} + +func (c *CommonModel) BeforeCreate(db *gorm.DB) { + if c.ID == 0 { + id := snowflake.GenerateID() + if id < 0 { + id = snowflake.GenerateID() + } + c.ID = uint(id) + } +} diff --git a/model/procedures.go b/model/procedures.go index 79e3842..98815f4 100644 --- a/model/procedures.go +++ b/model/procedures.go @@ -12,7 +12,7 @@ type ( Procedures struct { - gorm.Model + CommonModel ProductProcedureID string `gorm:"index;type:varchar(191);" json:"productProcedureID"` //浜у搧宸ュ簭id WorkOrderID string `gorm:"index;type:varchar(191);" json:"-"` OrderID string `gorm:"index;type:varchar(191);" json:"-"` diff --git a/pkg/snowflake/snowflake.go b/pkg/snowflake/snowflake.go index ad86994..cf134be 100644 --- a/pkg/snowflake/snowflake.go +++ b/pkg/snowflake/snowflake.go @@ -1,118 +1,62 @@ package snowflake import ( - "errors" - "strconv" - "sync" - "time" + "apsClient/pkg/logx" + "fmt" + "github.com/bwmarrin/snowflake" + "hash/fnv" + "net" ) -const ( - CEpoch = 1474802888000 - CWorkerIdBits = 10 // Num of WorkerId Bits - CSenquenceBits = 12 // Num of Sequence Bits +var Node *snowflake.Node - CWorkerIdShift = 12 - CTimeStampShift = 22 - - CSequenceMask = 0xfff // equal as getSequenceMask() - CMaxWorker = 0x3ff // equal as getMaxWorkerId() -) - -type IdWorker struct { - workerId int64 - lastTimeStamp int64 - sequence int64 - maxWorkerId int64 - lock *sync.Mutex -} - -func NewIdWorker(workerId int64) (iw *IdWorker, err error) { - iw = new(IdWorker) - - iw.maxWorkerId = getMaxWorkerId() - - if workerId > iw.maxWorkerId || workerId < 0 { - return nil, errors.New("worker not fit") +func Init(nodeId string) error { + // Create a new Node with a Node number of 1 + var err error + nodeIdInt, err := StringToNumber(nodeId) + if err != nil { + logx.Errorf("snowflake Init error:%v", err) + return err } - iw.workerId = workerId - iw.lastTimeStamp = -1 - iw.sequence = 0 - iw.lock = new(sync.Mutex) - return iw, nil -} - -func getMaxWorkerId() int64 { - return -1 ^ -1<<CWorkerIdBits -} - -func getSequenceMask() int64 { - return -1 ^ -1<<CSenquenceBits -} - -// return in ms -func (iw *IdWorker) timeGen() int64 { - return time.Now().UnixNano() / 1000 / 1000 -} - -func (iw *IdWorker) timeReGen(last int64) int64 { - ts := time.Now().UnixNano() / 1000 / 1000 - for { - if ts <= last { - ts = iw.timeGen() - } else { - break - } + Node, err = snowflake.NewNode(nodeIdInt) + if err != nil { + logx.Errorf("snowflake NewNode error:%v", err) + return err } - return ts + return nil } -func (iw *IdWorker) NextId() (ts int64, err error) { - iw.lock.Lock() - defer iw.lock.Unlock() - ts = iw.timeGen() - if ts == iw.lastTimeStamp { - iw.sequence = (iw.sequence + 1) & CSequenceMask - if iw.sequence == 0 { - ts = iw.timeReGen(ts) - } - } else { - iw.sequence = 0 - } - - if ts < iw.lastTimeStamp { - err = errors.New("Clock moved backwards, Refuse gen id") +func StringToNumber(input string) (int64, error) { + hash := fnv.New32a() + _, err := hash.Write([]byte(input)) + if err != nil { return 0, err } - iw.lastTimeStamp = ts - ts = (ts-CEpoch)<<CTimeStampShift | iw.workerId<<CWorkerIdShift | iw.sequence - return ts, nil + hashValue := int64(hash.Sum32()) + return hashValue, nil } -func ParseId(id int64) (t time.Time, ts int64, workerId int64, seq int64) { - seq = id & CSequenceMask - workerId = (id >> CWorkerIdShift) & CMaxWorker - ts = (id >> CTimeStampShift) + CEpoch - t = time.Unix(ts/1000, (ts%1000)*1000000) - return -} - -var idGenerater, _ = NewIdWorker(0) - -func GenerateId() int64 { -start: - id, err := idGenerater.NextId() - if err != nil { - goto start +func GenerateID() int64 { + if Node == nil { + // 浣跨敤 LookupIP 鑾峰彇涓绘満鐨� IP 鍦板潃鍒楄〃 + addrs, err := net.LookupIP("localhost") + if err != nil { + logx.Infof("snowflake can not generate, init error, get ip error:%v", err) + panic(fmt.Sprintf("snowflake can not generate, init error, get ip error:%v", err)) + } + var ip string + // 閬嶅巻 IP 鍦板潃鍒楄〃 + for _, addr := range addrs { + // 鍒ゆ柇 IP 鍦板潃鐨勭増鏈槸 IPv4 杩樻槸 IPv6 + if ipNet := addr.To4(); ipNet != nil { + ip = ipNet.String() + fmt.Printf("IPv4 Address: %s\n", ipNet.String()) + } + } + err = Init(ip) + if err != nil { + panic(fmt.Sprintf("snowflake can not generate, init error,:%v", err)) + } } - return id -} - -func GenerateIdStr() string { -start: - id, err := idGenerater.NextId() - if err != nil { - goto start - } - return strconv.FormatInt(id, 10) + return int64(Node.Generate()) } diff --git a/service/report_work.go b/service/report_work.go index ea25a57..4d7a0cb 100644 --- a/service/report_work.go +++ b/service/report_work.go @@ -10,6 +10,7 @@ "encoding/json" "errors" "github.com/jinzhu/gorm" + "github.com/spf13/cast" "time" ) @@ -65,7 +66,7 @@ WorkerID: params.WorkerID, WorkerName: workerName, WorkerTime: nowTs - startTs, - BarCode: snowflake.GenerateIdStr(), + BarCode: cast.ToString(snowflake.GenerateID()), } err = model.WithTransaction(func(db *gorm.DB) error { err = model.NewReportWorkSearch(db).Create(record) -- Gitblit v1.8.0