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