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